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 "process.hpp"
18ef3aeadcSPatrick Venture
19ef3aeadcSPatrick Venture #include "ipmi.hpp"
20ef3aeadcSPatrick Venture
21de8a16e2SPatrick Venture #include <ipmiblob/crc.hpp>
22067ece15SWilly Tu #include <ipmid/api-types.hpp>
23*52509572SPatrick Williams
24*52509572SPatrick Williams #include <cstring>
25067ece15SWilly Tu #include <span>
26b15b3050SPatrick Venture #include <unordered_map>
27067ece15SWilly Tu #include <utility>
28ef3aeadcSPatrick Venture #include <vector>
29ef3aeadcSPatrick Venture
30ef3aeadcSPatrick Venture namespace blobs
31ef3aeadcSPatrick Venture {
32ef3aeadcSPatrick Venture
33ef3aeadcSPatrick Venture /* Used by all commands with data. */
34ef3aeadcSPatrick Venture struct BmcRx
35ef3aeadcSPatrick Venture {
36ef3aeadcSPatrick Venture uint16_t crc;
37ef3aeadcSPatrick Venture uint8_t data; /* one byte minimum of data. */
38ef3aeadcSPatrick Venture } __attribute__((packed));
39ef3aeadcSPatrick Venture
40b15b3050SPatrick Venture static const std::unordered_map<BlobOEMCommands, IpmiBlobHandler> handlers = {
41b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobGetCount, getBlobCount},
42b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobEnumerate, enumerateBlob},
43b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobOpen, openBlob},
44b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobRead, readBlob},
45b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobWrite, writeBlob},
46b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobCommit, commitBlob},
47b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobClose, closeBlob},
48b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobDelete, deleteBlob},
49b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobStat, statBlob},
50b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobSessionStat, sessionStatBlob},
515c4b17b2SPatrick Venture {BlobOEMCommands::bmcBlobWriteMeta, writeMeta},
52b15b3050SPatrick Venture };
53b15b3050SPatrick Venture
validateBlobCommand(uint8_t cmd,std::span<const uint8_t> data)54067ece15SWilly Tu IpmiBlobHandler validateBlobCommand(uint8_t cmd, std::span<const uint8_t> data)
55ef3aeadcSPatrick Venture {
56067ece15SWilly Tu size_t requestLength = data.size();
57ef3aeadcSPatrick Venture /* We know dataLen is at least 1 already */
58067ece15SWilly Tu auto command = static_cast<BlobOEMCommands>(cmd);
59ef3aeadcSPatrick Venture
60ef3aeadcSPatrick Venture /* Validate it's at least well-formed. */
61ef3aeadcSPatrick Venture if (!validateRequestLength(command, requestLength))
62ef3aeadcSPatrick Venture {
63067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) {
64067ece15SWilly Tu return ipmi::responseReqDataLenInvalid();
65067ece15SWilly Tu };
66ef3aeadcSPatrick Venture }
67ef3aeadcSPatrick Venture
68ef3aeadcSPatrick Venture /* If there is a payload. */
69067ece15SWilly Tu if (requestLength > sizeof(cmd))
70ef3aeadcSPatrick Venture {
71ef3aeadcSPatrick Venture /* Verify the request includes: command, crc16, data */
72ef3aeadcSPatrick Venture if (requestLength < sizeof(struct BmcRx))
73ef3aeadcSPatrick Venture {
74067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) {
75067ece15SWilly Tu return ipmi::responseReqDataLenInvalid();
76067ece15SWilly Tu };
77ef3aeadcSPatrick Venture }
78ef3aeadcSPatrick Venture
79ef3aeadcSPatrick Venture /* We don't include the command byte at offset 0 as part of the crc
80ef3aeadcSPatrick Venture * payload area or the crc bytes at the beginning.
81ef3aeadcSPatrick Venture */
82ef3aeadcSPatrick Venture size_t requestBodyLen = requestLength - 3;
83ef3aeadcSPatrick Venture
84ef3aeadcSPatrick Venture /* We start after the command byte. */
85ef3aeadcSPatrick Venture std::vector<uint8_t> bytes(requestBodyLen);
86ef3aeadcSPatrick Venture
87067ece15SWilly Tu /* It likely has a well-formed payload.
88067ece15SWilly Tu * Get the first two bytes of the request for crc.
89067ece15SWilly Tu */
90067ece15SWilly Tu uint16_t crc;
91067ece15SWilly Tu if (data.size() < sizeof(crc))
92067ece15SWilly Tu {
93067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) {
94067ece15SWilly Tu return ipmi::responseReqDataLenInvalid();
95067ece15SWilly Tu };
96067ece15SWilly Tu }
97067ece15SWilly Tu std::memcpy(&crc, data.data(), sizeof(crc));
98ef3aeadcSPatrick Venture
99067ece15SWilly Tu /* Set the in-place CRC to zero.
100067ece15SWilly Tu * Remove the first two bytes for crc and get the reset of the request.
101067ece15SWilly Tu */
102067ece15SWilly Tu data = data.subspan(sizeof(crc));
103ef3aeadcSPatrick Venture
104ef3aeadcSPatrick Venture /* Crc expected but didn't match. */
105067ece15SWilly Tu if (crc != ipmiblob::generateCrc(
106067ece15SWilly Tu std::vector<uint8_t>(data.begin(), data.end())))
107ef3aeadcSPatrick Venture {
108067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) {
109067ece15SWilly Tu return ipmi::responseUnspecifiedError();
110067ece15SWilly Tu };
111067ece15SWilly Tu };
112ef3aeadcSPatrick Venture }
113ef3aeadcSPatrick Venture
114b15b3050SPatrick Venture /* Grab the corresponding handler for the command. */
115b15b3050SPatrick Venture auto found = handlers.find(command);
116b15b3050SPatrick Venture if (found == handlers.end())
117ef3aeadcSPatrick Venture {
118067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) {
119067ece15SWilly Tu return ipmi::responseInvalidFieldRequest();
120067ece15SWilly Tu };
121ef3aeadcSPatrick Venture }
122ef3aeadcSPatrick Venture
123b15b3050SPatrick Venture return found->second;
124ef3aeadcSPatrick Venture }
125ef3aeadcSPatrick Venture
processBlobCommand(IpmiBlobHandler cmd,ManagerInterface * mgr,std::span<const uint8_t> data,size_t maxSize)126067ece15SWilly Tu Resp processBlobCommand(IpmiBlobHandler cmd, ManagerInterface* mgr,
12783f9992cSWilly Tu std::span<const uint8_t> data, size_t maxSize)
128ef3aeadcSPatrick Venture {
129067ece15SWilly Tu Resp result = cmd(mgr, data);
130067ece15SWilly Tu if (std::get<0>(result) != ipmi::ccSuccess)
131ef3aeadcSPatrick Venture {
132ef3aeadcSPatrick Venture return result;
133ef3aeadcSPatrick Venture }
134ef3aeadcSPatrick Venture
135067ece15SWilly Tu std::vector<uint8_t>& response = std::get<0>(
136067ece15SWilly Tu // std::variant<std::vector<uint8_t>>
137067ece15SWilly Tu *std::get<1>(result));
138067ece15SWilly Tu size_t replyLength = response.size();
139ef3aeadcSPatrick Venture
140ef3aeadcSPatrick Venture /* The command, whatever it was, returned success. */
141ef3aeadcSPatrick Venture if (replyLength == 0)
142ef3aeadcSPatrick Venture {
143ef3aeadcSPatrick Venture return result;
144ef3aeadcSPatrick Venture }
145ef3aeadcSPatrick Venture
146d1c3e86fSPatrick Venture /* Read can return 0 bytes, and just a CRC, otherwise you need a CRC and 1
147d1c3e86fSPatrick Venture * byte, therefore the limit is 2 bytes.
148d1c3e86fSPatrick Venture */
149d1c3e86fSPatrick Venture if (replyLength < (sizeof(uint16_t)))
150ef3aeadcSPatrick Venture {
151067ece15SWilly Tu return ipmi::responseUnspecifiedError();
152ef3aeadcSPatrick Venture }
153ef3aeadcSPatrick Venture
15483f9992cSWilly Tu /* Make sure the reply size fits the ipmi buffer */
15583f9992cSWilly Tu if (replyLength > maxSize)
15683f9992cSWilly Tu {
15783f9992cSWilly Tu return ipmi::responseResponseError();
15883f9992cSWilly Tu }
15983f9992cSWilly Tu
160ef3aeadcSPatrick Venture /* The command, whatever it was, replied, so let's set the CRC. */
161067ece15SWilly Tu std::span<const uint8_t> responseView = response;
162067ece15SWilly Tu responseView = responseView.subspan(sizeof(uint16_t));
163067ece15SWilly Tu std::vector<std::uint8_t> crcBuffer(responseView.begin(),
164067ece15SWilly Tu responseView.end());
165ef3aeadcSPatrick Venture /* Copy the CRC into place. */
166de8a16e2SPatrick Venture uint16_t crcValue = ipmiblob::generateCrc(crcBuffer);
167067ece15SWilly Tu if (response.size() < sizeof(crcValue))
168067ece15SWilly Tu {
169067ece15SWilly Tu return ipmi::responseReqDataLenInvalid();
170067ece15SWilly Tu }
171067ece15SWilly Tu std::memcpy(response.data(), &crcValue, sizeof(crcValue));
172ef3aeadcSPatrick Venture
173ef3aeadcSPatrick Venture return result;
174ef3aeadcSPatrick Venture }
17503fd5b8bSPatrick Venture
handleBlobCommand(uint8_t cmd,std::vector<uint8_t> data,size_t maxSize)17683f9992cSWilly Tu Resp handleBlobCommand(uint8_t cmd, std::vector<uint8_t> data, size_t maxSize)
17703fd5b8bSPatrick Venture {
17803fd5b8bSPatrick Venture /* on failure rc is set to the corresponding IPMI error. */
179067ece15SWilly Tu return processBlobCommand(validateBlobCommand(cmd, data), getBlobManager(),
18083f9992cSWilly Tu data, maxSize);
18103fd5b8bSPatrick Venture }
18203fd5b8bSPatrick Venture
183ef3aeadcSPatrick Venture } // namespace blobs
184