blob: 5718e3cf184337ea898e4e808f335e8dea2c1363 [file] [log] [blame]
Patrick Ventureef3aead2018-09-12 08:53:29 -07001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "ipmi.hpp"
18
19#include <cstring>
Willy Tu067ece12022-06-16 02:07:06 -070020#include <span>
Patrick Ventureef3aead2018-09-12 08:53:29 -070021#include <string>
22#include <unordered_map>
23
24namespace blobs
25{
26
27bool validateRequestLength(BlobOEMCommands command, size_t requestLen)
28{
29 /* The smallest string is one letter and the nul-terminator. */
30 static const int kMinStrLen = 2;
31
32 static const std::unordered_map<BlobOEMCommands, size_t> minimumLengths = {
33 {BlobOEMCommands::bmcBlobEnumerate, sizeof(struct BmcBlobEnumerateTx)},
34 {BlobOEMCommands::bmcBlobOpen,
35 sizeof(struct BmcBlobOpenTx) + kMinStrLen},
36 {BlobOEMCommands::bmcBlobClose, sizeof(struct BmcBlobCloseTx)},
37 {BlobOEMCommands::bmcBlobDelete,
38 sizeof(struct BmcBlobDeleteTx) + kMinStrLen},
39 {BlobOEMCommands::bmcBlobStat,
40 sizeof(struct BmcBlobStatTx) + kMinStrLen},
41 {BlobOEMCommands::bmcBlobSessionStat,
42 sizeof(struct BmcBlobSessionStatTx)},
43 {BlobOEMCommands::bmcBlobCommit, sizeof(struct BmcBlobCommitTx)},
44 {BlobOEMCommands::bmcBlobRead, sizeof(struct BmcBlobReadTx)},
45 {BlobOEMCommands::bmcBlobWrite,
46 sizeof(struct BmcBlobWriteTx) + sizeof(uint8_t)},
Patrick Venture5c4b17b2018-10-04 10:32:22 -070047 {BlobOEMCommands::bmcBlobWriteMeta,
48 sizeof(struct BmcBlobWriteMetaTx) + sizeof(uint8_t)},
Patrick Ventureef3aead2018-09-12 08:53:29 -070049 };
50
51 auto results = minimumLengths.find(command);
52 if (results == minimumLengths.end())
53 {
54 /* Valid length by default if we don't care. */
55 return true;
56 }
57
58 /* If the request is shorter than the minimum, it's invalid. */
59 if (requestLen < results->second)
60 {
61 return false;
62 }
63
64 return true;
65}
66
Willy Tu067ece12022-06-16 02:07:06 -070067std::string stringFromBuffer(std::span<const uint8_t> data)
Patrick Ventureef3aead2018-09-12 08:53:29 -070068{
Willy Tu067ece12022-06-16 02:07:06 -070069 if (data.empty() || data.back() != '\0')
Patrick Ventureef3aead2018-09-12 08:53:29 -070070 {
Willy Tu067ece12022-06-16 02:07:06 -070071 return std::string();
Patrick Ventureef3aead2018-09-12 08:53:29 -070072 }
73
Willy Tu067ece12022-06-16 02:07:06 -070074 // Last index is nul-terminator.
75 return std::string(data.begin(), data.end() - 1);
Patrick Ventureef3aead2018-09-12 08:53:29 -070076}
77
Willy Tu067ece12022-06-16 02:07:06 -070078Resp getBlobCount(ManagerInterface* mgr, std::span<const uint8_t>)
Patrick Ventureef3aead2018-09-12 08:53:29 -070079{
80 struct BmcBlobCountRx resp;
81 resp.crc = 0;
82 resp.blobCount = mgr->buildBlobList();
83
84 /* Copy the response into the reply buffer */
Willy Tu067ece12022-06-16 02:07:06 -070085 std::vector<uint8_t> output(sizeof(BmcBlobCountRx), 0);
86 std::memcpy(output.data(), &resp, sizeof(resp));
Patrick Ventureef3aead2018-09-12 08:53:29 -070087
Willy Tu067ece12022-06-16 02:07:06 -070088 return ipmi::responseSuccess(output);
Patrick Ventureef3aead2018-09-12 08:53:29 -070089}
90
Willy Tu067ece12022-06-16 02:07:06 -070091Resp enumerateBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
Patrick Ventureef3aead2018-09-12 08:53:29 -070092{
93 /* Verify datalen is >= sizeof(request) */
94 struct BmcBlobEnumerateTx request;
Patrick Ventureef3aead2018-09-12 08:53:29 -070095
Willy Tu067ece12022-06-16 02:07:06 -070096 std::memcpy(&request, data.data(), sizeof(request));
Patrick Ventureef3aead2018-09-12 08:53:29 -070097
98 std::string blobId = mgr->getBlobId(request.blobIdx);
Willy Tu3d1fdfa2022-02-08 16:05:15 -080099 if (blobId.empty())
Patrick Ventureef3aead2018-09-12 08:53:29 -0700100 {
Willy Tu067ece12022-06-16 02:07:06 -0700101 return ipmi::responseInvalidFieldRequest();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700102 }
103
Willy Tu067ece12022-06-16 02:07:06 -0700104 std::vector<uint8_t> output(sizeof(BmcBlobEnumerateRx), 0);
105 output.insert(output.end(), blobId.c_str(),
106 blobId.c_str() + blobId.length() + 1);
107 return ipmi::responseSuccess(output);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700108}
109
Willy Tu067ece12022-06-16 02:07:06 -0700110Resp openBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700111{
Willy Tu067ece12022-06-16 02:07:06 -0700112 auto request = reinterpret_cast<const struct BmcBlobOpenTx*>(data.data());
Patrick Ventureef3aead2018-09-12 08:53:29 -0700113 uint16_t session;
114
Willy Tu067ece12022-06-16 02:07:06 -0700115 std::string path = stringFromBuffer(data.subspan(sizeof(BmcBlobOpenTx)));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700116 if (path.empty())
117 {
Willy Tu067ece12022-06-16 02:07:06 -0700118 return ipmi::responseReqDataLenInvalid();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700119 }
120
121 /* Attempt to open. */
122 if (!mgr->open(request->flags, path, &session))
123 {
Willy Tu067ece12022-06-16 02:07:06 -0700124 return ipmi::responseUnspecifiedError();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700125 }
126
127 struct BmcBlobOpenRx reply;
128 reply.crc = 0;
129 reply.sessionId = session;
130
Willy Tu067ece12022-06-16 02:07:06 -0700131 std::vector<uint8_t> output(sizeof(BmcBlobOpenRx), 0);
132 std::memcpy(output.data(), &reply, sizeof(reply));
133 return ipmi::responseSuccess(output);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700134}
135
Willy Tu067ece12022-06-16 02:07:06 -0700136Resp closeBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700137{
138 struct BmcBlobCloseTx request;
Willy Tu067ece12022-06-16 02:07:06 -0700139 if (data.size() < sizeof(request))
140 {
141 return ipmi::responseReqDataLenInvalid();
142 }
143 std::memcpy(&request, data.data(), sizeof(request));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700144
145 /* Attempt to close. */
146 if (!mgr->close(request.sessionId))
147 {
Willy Tu067ece12022-06-16 02:07:06 -0700148 return ipmi::responseUnspecifiedError();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700149 }
150
Willy Tu067ece12022-06-16 02:07:06 -0700151 return ipmi::responseSuccess(std::vector<uint8_t>{});
Patrick Ventureef3aead2018-09-12 08:53:29 -0700152}
153
Willy Tu067ece12022-06-16 02:07:06 -0700154Resp deleteBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700155{
Willy Tu067ece12022-06-16 02:07:06 -0700156 std::string path = stringFromBuffer(data.subspan(sizeof(BmcBlobDeleteTx)));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700157 if (path.empty())
158 {
Willy Tu067ece12022-06-16 02:07:06 -0700159 return ipmi::responseReqDataLenInvalid();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700160 }
161
162 /* Attempt to delete. */
163 if (!mgr->deleteBlob(path))
164 {
Willy Tu067ece12022-06-16 02:07:06 -0700165 return ipmi::responseUnspecifiedError();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700166 }
167
Willy Tu067ece12022-06-16 02:07:06 -0700168 return ipmi::responseSuccess(std::vector<uint8_t>{});
Patrick Ventureef3aead2018-09-12 08:53:29 -0700169}
170
Willy Tu067ece12022-06-16 02:07:06 -0700171static Resp returnStatBlob(BlobMeta* meta)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700172{
173 struct BmcBlobStatRx reply;
174 reply.crc = 0;
175 reply.blobState = meta->blobState;
176 reply.size = meta->size;
177 reply.metadataLen = meta->metadata.size();
178
Willy Tu067ece12022-06-16 02:07:06 -0700179 std::vector<uint8_t> output(sizeof(BmcBlobStatRx), 0);
180 std::memcpy(output.data(), &reply, sizeof(reply));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700181
Willy Tu067ece12022-06-16 02:07:06 -0700182 /* If there is metadata, insert it to output. */
Willy Tu3d1fdfa2022-02-08 16:05:15 -0800183 if (!meta->metadata.empty())
Patrick Ventureef3aead2018-09-12 08:53:29 -0700184 {
Willy Tu067ece12022-06-16 02:07:06 -0700185 output.insert(output.end(), meta->metadata.begin(),
186 meta->metadata.end());
Patrick Ventureef3aead2018-09-12 08:53:29 -0700187 }
Willy Tu067ece12022-06-16 02:07:06 -0700188 return ipmi::responseSuccess(output);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700189}
190
Willy Tu067ece12022-06-16 02:07:06 -0700191Resp statBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700192{
Willy Tu067ece12022-06-16 02:07:06 -0700193 std::string path = stringFromBuffer(data.subspan(sizeof(BmcBlobStatTx)));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700194 if (path.empty())
195 {
Willy Tu067ece12022-06-16 02:07:06 -0700196 return ipmi::responseReqDataLenInvalid();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700197 }
198
199 /* Attempt to stat. */
Patrick Venture8bc11772019-06-04 07:20:24 -0700200 BlobMeta meta;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700201 if (!mgr->stat(path, &meta))
202 {
Willy Tu067ece12022-06-16 02:07:06 -0700203 return ipmi::responseUnspecifiedError();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700204 }
205
Willy Tu067ece12022-06-16 02:07:06 -0700206 return returnStatBlob(&meta);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700207}
208
Willy Tu067ece12022-06-16 02:07:06 -0700209Resp sessionStatBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700210{
211 struct BmcBlobSessionStatTx request;
Willy Tu067ece12022-06-16 02:07:06 -0700212 if (data.size() < sizeof(request))
213 {
214 return ipmi::responseReqDataLenInvalid();
215 }
216 std::memcpy(&request, data.data(), sizeof(request));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700217
218 /* Attempt to stat. */
Patrick Venture8bc11772019-06-04 07:20:24 -0700219 BlobMeta meta;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700220
221 if (!mgr->stat(request.sessionId, &meta))
222 {
Willy Tu067ece12022-06-16 02:07:06 -0700223 return ipmi::responseUnspecifiedError();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700224 }
225
Willy Tu067ece12022-06-16 02:07:06 -0700226 return returnStatBlob(&meta);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700227}
228
Willy Tu067ece12022-06-16 02:07:06 -0700229Resp commitBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700230{
Willy Tu067ece12022-06-16 02:07:06 -0700231 auto request = reinterpret_cast<const struct BmcBlobCommitTx*>(data.data());
Patrick Ventureef3aead2018-09-12 08:53:29 -0700232
233 /* Sanity check the commitDataLen */
Willy Tu067ece12022-06-16 02:07:06 -0700234 if (request->commitDataLen > (data.size() - sizeof(struct BmcBlobCommitTx)))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700235 {
Willy Tu067ece12022-06-16 02:07:06 -0700236 return ipmi::responseReqDataLenInvalid();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700237 }
238
Willy Tu067ece12022-06-16 02:07:06 -0700239 data = data.subspan(sizeof(struct BmcBlobCommitTx), request->commitDataLen);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700240
Willy Tu067ece12022-06-16 02:07:06 -0700241 if (!mgr->commit(request->sessionId,
242 std::vector<uint8_t>(data.begin(), data.end())))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700243 {
Willy Tu067ece12022-06-16 02:07:06 -0700244 return ipmi::responseUnspecifiedError();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700245 }
246
Willy Tu067ece12022-06-16 02:07:06 -0700247 return ipmi::responseSuccess(std::vector<uint8_t>{});
Patrick Ventureef3aead2018-09-12 08:53:29 -0700248}
249
Willy Tu067ece12022-06-16 02:07:06 -0700250Resp readBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700251{
252 struct BmcBlobReadTx request;
Willy Tu067ece12022-06-16 02:07:06 -0700253 if (data.size() < sizeof(request))
254 {
255 return ipmi::responseReqDataLenInvalid();
256 }
257 std::memcpy(&request, data.data(), sizeof(request));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700258
Patrick Williams97e69ca2024-08-16 15:21:49 -0400259 std::vector<uint8_t> result =
260 mgr->read(request.sessionId, request.offset, request.requestedSize);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700261
262 /* If the Read fails, it returns success but with only the crc and 0 bytes
263 * of data.
264 * If there was data returned, copy into the reply buffer.
265 */
Willy Tu067ece12022-06-16 02:07:06 -0700266 std::vector<uint8_t> output(sizeof(BmcBlobReadRx), 0);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700267
Willy Tu3d1fdfa2022-02-08 16:05:15 -0800268 if (!result.empty())
Patrick Ventureef3aead2018-09-12 08:53:29 -0700269 {
Willy Tu067ece12022-06-16 02:07:06 -0700270 output.insert(output.end(), result.begin(), result.end());
Patrick Ventureef3aead2018-09-12 08:53:29 -0700271 }
272
Willy Tu067ece12022-06-16 02:07:06 -0700273 return ipmi::responseSuccess(output);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700274}
275
Willy Tu067ece12022-06-16 02:07:06 -0700276Resp writeBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700277{
Willy Tu067ece12022-06-16 02:07:06 -0700278 auto request = reinterpret_cast<const struct BmcBlobWriteTx*>(data.data());
279 data = data.subspan(sizeof(struct BmcBlobWriteTx));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700280
281 /* Attempt to write the bytes. */
Willy Tu067ece12022-06-16 02:07:06 -0700282 if (!mgr->write(request->sessionId, request->offset,
283 std::vector<uint8_t>(data.begin(), data.end())))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700284 {
Willy Tu067ece12022-06-16 02:07:06 -0700285 return ipmi::responseUnspecifiedError();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700286 }
287
Willy Tu067ece12022-06-16 02:07:06 -0700288 return ipmi::responseSuccess(std::vector<uint8_t>{});
Patrick Ventureef3aead2018-09-12 08:53:29 -0700289}
290
Willy Tu067ece12022-06-16 02:07:06 -0700291Resp writeMeta(ManagerInterface* mgr, std::span<const uint8_t> data)
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700292{
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700293 struct BmcBlobWriteMetaTx request;
Willy Tu067ece12022-06-16 02:07:06 -0700294 if (data.size() < sizeof(request))
295 {
296 return ipmi::responseReqDataLenInvalid();
297 }
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700298
299 /* Copy over the request. */
Willy Tu067ece12022-06-16 02:07:06 -0700300 std::memcpy(&request, data.data(), sizeof(request));
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700301
302 /* Nothing really else to validate, we just copy those bytes. */
Willy Tu067ece12022-06-16 02:07:06 -0700303 data = data.subspan(sizeof(struct BmcBlobWriteMetaTx));
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700304
305 /* Attempt to write the bytes. */
Willy Tu067ece12022-06-16 02:07:06 -0700306 if (!mgr->writeMeta(request.sessionId, request.offset,
307 std::vector<uint8_t>(data.begin(), data.end())))
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700308 {
Willy Tu067ece12022-06-16 02:07:06 -0700309 return ipmi::responseUnspecifiedError();
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700310 }
311
Willy Tu067ece12022-06-16 02:07:06 -0700312 return ipmi::responseSuccess(std::vector<uint8_t>{});
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700313}
314
Patrick Ventureef3aead2018-09-12 08:53:29 -0700315} // namespace blobs