xref: /openbmc/phosphor-ipmi-blobs/process.cpp (revision 83f9992cc60dedb6a2a964a733fd35c89c8a0cfa)
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 
21ef3aeadcSPatrick Venture #include <cstring>
22de8a16e2SPatrick Venture #include <ipmiblob/crc.hpp>
23067ece15SWilly Tu #include <ipmid/api-types.hpp>
24067ece15SWilly Tu #include <span>
25b15b3050SPatrick Venture #include <unordered_map>
26067ece15SWilly Tu #include <utility>
27ef3aeadcSPatrick Venture #include <vector>
28ef3aeadcSPatrick Venture 
29ef3aeadcSPatrick Venture namespace blobs
30ef3aeadcSPatrick Venture {
31ef3aeadcSPatrick Venture 
32ef3aeadcSPatrick Venture /* Used by all commands with data. */
33ef3aeadcSPatrick Venture struct BmcRx
34ef3aeadcSPatrick Venture {
35ef3aeadcSPatrick Venture     uint16_t crc;
36ef3aeadcSPatrick Venture     uint8_t data; /* one byte minimum of data. */
37ef3aeadcSPatrick Venture } __attribute__((packed));
38ef3aeadcSPatrick Venture 
39b15b3050SPatrick Venture static const std::unordered_map<BlobOEMCommands, IpmiBlobHandler> handlers = {
40b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobGetCount, getBlobCount},
41b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobEnumerate, enumerateBlob},
42b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobOpen, openBlob},
43b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobRead, readBlob},
44b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobWrite, writeBlob},
45b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobCommit, commitBlob},
46b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobClose, closeBlob},
47b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobDelete, deleteBlob},
48b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobStat, statBlob},
49b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobSessionStat, sessionStatBlob},
505c4b17b2SPatrick Venture     {BlobOEMCommands::bmcBlobWriteMeta, writeMeta},
51b15b3050SPatrick Venture };
52b15b3050SPatrick Venture 
53067ece15SWilly Tu IpmiBlobHandler validateBlobCommand(uint8_t cmd, std::span<const uint8_t> data)
54ef3aeadcSPatrick Venture {
55067ece15SWilly Tu     size_t requestLength = data.size();
56ef3aeadcSPatrick Venture     /* We know dataLen is at least 1 already */
57067ece15SWilly Tu     auto command = static_cast<BlobOEMCommands>(cmd);
58ef3aeadcSPatrick Venture 
59ef3aeadcSPatrick Venture     /* Validate it's at least well-formed. */
60ef3aeadcSPatrick Venture     if (!validateRequestLength(command, requestLength))
61ef3aeadcSPatrick Venture     {
62067ece15SWilly Tu         return [](ManagerInterface*, std::span<const uint8_t>) {
63067ece15SWilly Tu             return ipmi::responseReqDataLenInvalid();
64067ece15SWilly Tu         };
65ef3aeadcSPatrick Venture     }
66ef3aeadcSPatrick Venture 
67ef3aeadcSPatrick Venture     /* If there is a payload. */
68067ece15SWilly Tu     if (requestLength > sizeof(cmd))
69ef3aeadcSPatrick Venture     {
70ef3aeadcSPatrick Venture         /* Verify the request includes: command, crc16, data */
71ef3aeadcSPatrick Venture         if (requestLength < sizeof(struct BmcRx))
72ef3aeadcSPatrick Venture         {
73067ece15SWilly Tu             return [](ManagerInterface*, std::span<const uint8_t>) {
74067ece15SWilly Tu                 return ipmi::responseReqDataLenInvalid();
75067ece15SWilly Tu             };
76ef3aeadcSPatrick Venture         }
77ef3aeadcSPatrick Venture 
78ef3aeadcSPatrick Venture         /* We don't include the command byte at offset 0 as part of the crc
79ef3aeadcSPatrick Venture          * payload area or the crc bytes at the beginning.
80ef3aeadcSPatrick Venture          */
81ef3aeadcSPatrick Venture         size_t requestBodyLen = requestLength - 3;
82ef3aeadcSPatrick Venture 
83ef3aeadcSPatrick Venture         /* We start after the command byte. */
84ef3aeadcSPatrick Venture         std::vector<uint8_t> bytes(requestBodyLen);
85ef3aeadcSPatrick Venture 
86067ece15SWilly Tu         /* It likely has a well-formed payload.
87067ece15SWilly Tu          * Get the first two bytes of the request for crc.
88067ece15SWilly Tu          */
89067ece15SWilly Tu         uint16_t crc;
90067ece15SWilly Tu         if (data.size() < sizeof(crc))
91067ece15SWilly Tu         {
92067ece15SWilly Tu             return [](ManagerInterface*, std::span<const uint8_t>) {
93067ece15SWilly Tu                 return ipmi::responseReqDataLenInvalid();
94067ece15SWilly Tu             };
95067ece15SWilly Tu         }
96067ece15SWilly Tu         std::memcpy(&crc, data.data(), sizeof(crc));
97ef3aeadcSPatrick Venture 
98067ece15SWilly Tu         /* Set the in-place CRC to zero.
99067ece15SWilly Tu          * Remove the first two bytes for crc and get the reset of the request.
100067ece15SWilly Tu          */
101067ece15SWilly Tu         data = data.subspan(sizeof(crc));
102ef3aeadcSPatrick Venture 
103ef3aeadcSPatrick Venture         /* Crc expected but didn't match. */
104067ece15SWilly Tu         if (crc != ipmiblob::generateCrc(
105067ece15SWilly Tu                        std::vector<uint8_t>(data.begin(), data.end())))
106ef3aeadcSPatrick Venture         {
107067ece15SWilly Tu             return [](ManagerInterface*, std::span<const uint8_t>) {
108067ece15SWilly Tu                 return ipmi::responseUnspecifiedError();
109067ece15SWilly Tu             };
110067ece15SWilly Tu         };
111ef3aeadcSPatrick Venture     }
112ef3aeadcSPatrick Venture 
113b15b3050SPatrick Venture     /* Grab the corresponding handler for the command. */
114b15b3050SPatrick Venture     auto found = handlers.find(command);
115b15b3050SPatrick Venture     if (found == handlers.end())
116ef3aeadcSPatrick Venture     {
117067ece15SWilly Tu         return [](ManagerInterface*, std::span<const uint8_t>) {
118067ece15SWilly Tu             return ipmi::responseInvalidFieldRequest();
119067ece15SWilly Tu         };
120ef3aeadcSPatrick Venture     }
121ef3aeadcSPatrick Venture 
122b15b3050SPatrick Venture     return found->second;
123ef3aeadcSPatrick Venture }
124ef3aeadcSPatrick Venture 
125067ece15SWilly Tu Resp processBlobCommand(IpmiBlobHandler cmd, ManagerInterface* mgr,
126*83f9992cSWilly Tu                         std::span<const uint8_t> data, size_t maxSize)
127ef3aeadcSPatrick Venture {
128067ece15SWilly Tu     Resp result = cmd(mgr, data);
129067ece15SWilly Tu     if (std::get<0>(result) != ipmi::ccSuccess)
130ef3aeadcSPatrick Venture     {
131ef3aeadcSPatrick Venture         return result;
132ef3aeadcSPatrick Venture     }
133ef3aeadcSPatrick Venture 
134067ece15SWilly Tu     std::vector<uint8_t>& response = std::get<0>(
135067ece15SWilly Tu         // std::variant<std::vector<uint8_t>>
136067ece15SWilly Tu         *std::get<1>(result));
137067ece15SWilly Tu     size_t replyLength = response.size();
138ef3aeadcSPatrick Venture 
139ef3aeadcSPatrick Venture     /* The command, whatever it was, returned success. */
140ef3aeadcSPatrick Venture     if (replyLength == 0)
141ef3aeadcSPatrick Venture     {
142ef3aeadcSPatrick Venture         return result;
143ef3aeadcSPatrick Venture     }
144ef3aeadcSPatrick Venture 
145d1c3e86fSPatrick Venture     /* Read can return 0 bytes, and just a CRC, otherwise you need a CRC and 1
146d1c3e86fSPatrick Venture      * byte, therefore the limit is 2 bytes.
147d1c3e86fSPatrick Venture      */
148d1c3e86fSPatrick Venture     if (replyLength < (sizeof(uint16_t)))
149ef3aeadcSPatrick Venture     {
150067ece15SWilly Tu         return ipmi::responseUnspecifiedError();
151ef3aeadcSPatrick Venture     }
152ef3aeadcSPatrick Venture 
153*83f9992cSWilly Tu     /* Make sure the reply size fits the ipmi buffer */
154*83f9992cSWilly Tu     if (replyLength > maxSize)
155*83f9992cSWilly Tu     {
156*83f9992cSWilly Tu         return ipmi::responseResponseError();
157*83f9992cSWilly Tu     }
158*83f9992cSWilly Tu 
159ef3aeadcSPatrick Venture     /* The command, whatever it was, replied, so let's set the CRC. */
160067ece15SWilly Tu     std::span<const uint8_t> responseView = response;
161067ece15SWilly Tu     responseView = responseView.subspan(sizeof(uint16_t));
162067ece15SWilly Tu     std::vector<std::uint8_t> crcBuffer(responseView.begin(),
163067ece15SWilly Tu                                         responseView.end());
164ef3aeadcSPatrick Venture     /* Copy the CRC into place. */
165de8a16e2SPatrick Venture     uint16_t crcValue = ipmiblob::generateCrc(crcBuffer);
166067ece15SWilly Tu     if (response.size() < sizeof(crcValue))
167067ece15SWilly Tu     {
168067ece15SWilly Tu         return ipmi::responseReqDataLenInvalid();
169067ece15SWilly Tu     }
170067ece15SWilly Tu     std::memcpy(response.data(), &crcValue, sizeof(crcValue));
171ef3aeadcSPatrick Venture 
172ef3aeadcSPatrick Venture     return result;
173ef3aeadcSPatrick Venture }
17403fd5b8bSPatrick Venture 
175*83f9992cSWilly Tu Resp handleBlobCommand(uint8_t cmd, std::vector<uint8_t> data, size_t maxSize)
17603fd5b8bSPatrick Venture {
17703fd5b8bSPatrick Venture     /* on failure rc is set to the corresponding IPMI error. */
178067ece15SWilly Tu     return processBlobCommand(validateBlobCommand(cmd, data), getBlobManager(),
179*83f9992cSWilly Tu                               data, maxSize);
18003fd5b8bSPatrick Venture }
18103fd5b8bSPatrick Venture 
182ef3aeadcSPatrick Venture } // namespace blobs
183