xref: /openbmc/phosphor-ipmi-blobs/process.cpp (revision 5250957212ebf851d49df046acd6416a0d17c749)
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