xref: /openbmc/phosphor-ipmi-blobs/process.cpp (revision de8a16e2e85f49e142461b7e6fe901d3f8740fdf)
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>
22*de8a16e2SPatrick Venture #include <ipmiblob/crc.hpp>
23b15b3050SPatrick Venture #include <unordered_map>
24ef3aeadcSPatrick Venture #include <vector>
25ef3aeadcSPatrick Venture 
26ef3aeadcSPatrick Venture namespace blobs
27ef3aeadcSPatrick Venture {
28ef3aeadcSPatrick Venture 
29ef3aeadcSPatrick Venture /* Used by all commands with data. */
30ef3aeadcSPatrick Venture struct BmcRx
31ef3aeadcSPatrick Venture {
32ef3aeadcSPatrick Venture     uint8_t cmd;
33ef3aeadcSPatrick Venture     uint16_t crc;
34ef3aeadcSPatrick Venture     uint8_t data; /* one byte minimum of data. */
35ef3aeadcSPatrick Venture } __attribute__((packed));
36ef3aeadcSPatrick Venture 
37b15b3050SPatrick Venture static const std::unordered_map<BlobOEMCommands, IpmiBlobHandler> handlers = {
38b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobGetCount, getBlobCount},
39b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobEnumerate, enumerateBlob},
40b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobOpen, openBlob},
41b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobRead, readBlob},
42b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobWrite, writeBlob},
43b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobCommit, commitBlob},
44b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobClose, closeBlob},
45b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobDelete, deleteBlob},
46b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobStat, statBlob},
47b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobSessionStat, sessionStatBlob},
485c4b17b2SPatrick Venture     {BlobOEMCommands::bmcBlobWriteMeta, writeMeta},
49b15b3050SPatrick Venture };
50b15b3050SPatrick Venture 
51*de8a16e2SPatrick Venture IpmiBlobHandler validateBlobCommand(const uint8_t* reqBuf, uint8_t* replyCmdBuf,
52*de8a16e2SPatrick Venture                                     size_t* dataLen, ipmi_ret_t* code)
53ef3aeadcSPatrick Venture {
54ef3aeadcSPatrick Venture     size_t requestLength = (*dataLen);
55ef3aeadcSPatrick Venture     /* We know dataLen is at least 1 already */
56ef3aeadcSPatrick Venture     auto command = static_cast<BlobOEMCommands>(reqBuf[0]);
57ef3aeadcSPatrick Venture 
58ef3aeadcSPatrick Venture     /* Validate it's at least well-formed. */
59ef3aeadcSPatrick Venture     if (!validateRequestLength(command, requestLength))
60ef3aeadcSPatrick Venture     {
6141258800SPatrick Venture         *code = IPMI_CC_REQ_DATA_LEN_INVALID;
62ef3aeadcSPatrick Venture         return nullptr;
63ef3aeadcSPatrick Venture     }
64ef3aeadcSPatrick Venture 
65ef3aeadcSPatrick Venture     /* If there is a payload. */
66ef3aeadcSPatrick Venture     if (requestLength > sizeof(uint8_t))
67ef3aeadcSPatrick Venture     {
68ef3aeadcSPatrick Venture         /* Verify the request includes: command, crc16, data */
69ef3aeadcSPatrick Venture         if (requestLength < sizeof(struct BmcRx))
70ef3aeadcSPatrick Venture         {
7141258800SPatrick Venture             *code = IPMI_CC_REQ_DATA_LEN_INVALID;
72ef3aeadcSPatrick Venture             return nullptr;
73ef3aeadcSPatrick Venture         }
74ef3aeadcSPatrick Venture 
75ef3aeadcSPatrick Venture         /* We don't include the command byte at offset 0 as part of the crc
76ef3aeadcSPatrick Venture          * payload area or the crc bytes at the beginning.
77ef3aeadcSPatrick Venture          */
78ef3aeadcSPatrick Venture         size_t requestBodyLen = requestLength - 3;
79ef3aeadcSPatrick Venture 
80ef3aeadcSPatrick Venture         /* We start after the command byte. */
81ef3aeadcSPatrick Venture         std::vector<uint8_t> bytes(requestBodyLen);
82ef3aeadcSPatrick Venture 
83ef3aeadcSPatrick Venture         /* It likely has a well-formed payload. */
84ef3aeadcSPatrick Venture         struct BmcRx request;
85ef3aeadcSPatrick Venture         std::memcpy(&request, reqBuf, sizeof(request));
86ef3aeadcSPatrick Venture         uint16_t crcValue = request.crc;
87ef3aeadcSPatrick Venture 
88ef3aeadcSPatrick Venture         /* Set the in-place CRC to zero. */
89ef3aeadcSPatrick Venture         std::memcpy(bytes.data(), &reqBuf[3], requestBodyLen);
90ef3aeadcSPatrick Venture 
91ef3aeadcSPatrick Venture         /* Crc expected but didn't match. */
92*de8a16e2SPatrick Venture         if (crcValue != ipmiblob::generateCrc(bytes))
93ef3aeadcSPatrick Venture         {
9441258800SPatrick Venture             *code = IPMI_CC_UNSPECIFIED_ERROR;
95ef3aeadcSPatrick Venture             return nullptr;
96ef3aeadcSPatrick Venture         }
97ef3aeadcSPatrick Venture     }
98ef3aeadcSPatrick Venture 
99b15b3050SPatrick Venture     /* Grab the corresponding handler for the command. */
100b15b3050SPatrick Venture     auto found = handlers.find(command);
101b15b3050SPatrick Venture     if (found == handlers.end())
102ef3aeadcSPatrick Venture     {
10341258800SPatrick Venture         *code = IPMI_CC_INVALID_FIELD_REQUEST;
104ef3aeadcSPatrick Venture         return nullptr;
105ef3aeadcSPatrick Venture     }
106ef3aeadcSPatrick Venture 
107b15b3050SPatrick Venture     return found->second;
108ef3aeadcSPatrick Venture }
109ef3aeadcSPatrick Venture 
110ef3aeadcSPatrick Venture ipmi_ret_t processBlobCommand(IpmiBlobHandler cmd, ManagerInterface* mgr,
111*de8a16e2SPatrick Venture                               const uint8_t* reqBuf, uint8_t* replyCmdBuf,
112*de8a16e2SPatrick Venture                               size_t* dataLen)
113ef3aeadcSPatrick Venture {
114ef3aeadcSPatrick Venture     ipmi_ret_t result = cmd(mgr, reqBuf, replyCmdBuf, dataLen);
115ef3aeadcSPatrick Venture     if (result != IPMI_CC_OK)
116ef3aeadcSPatrick Venture     {
117ef3aeadcSPatrick Venture         return result;
118ef3aeadcSPatrick Venture     }
119ef3aeadcSPatrick Venture 
120ef3aeadcSPatrick Venture     size_t replyLength = (*dataLen);
121ef3aeadcSPatrick Venture 
122ef3aeadcSPatrick Venture     /* The command, whatever it was, returned success. */
123ef3aeadcSPatrick Venture     if (replyLength == 0)
124ef3aeadcSPatrick Venture     {
125ef3aeadcSPatrick Venture         return result;
126ef3aeadcSPatrick Venture     }
127ef3aeadcSPatrick Venture 
128d1c3e86fSPatrick Venture     /* Read can return 0 bytes, and just a CRC, otherwise you need a CRC and 1
129d1c3e86fSPatrick Venture      * byte, therefore the limit is 2 bytes.
130d1c3e86fSPatrick Venture      */
131d1c3e86fSPatrick Venture     if (replyLength < (sizeof(uint16_t)))
132ef3aeadcSPatrick Venture     {
13341258800SPatrick Venture         return IPMI_CC_UNSPECIFIED_ERROR;
134ef3aeadcSPatrick Venture     }
135ef3aeadcSPatrick Venture 
136ef3aeadcSPatrick Venture     /* The command, whatever it was, replied, so let's set the CRC. */
137*de8a16e2SPatrick Venture     std::vector<std::uint8_t> crcBuffer(replyCmdBuf + sizeof(uint16_t),
138*de8a16e2SPatrick Venture                                         replyCmdBuf + replyLength);
139ef3aeadcSPatrick Venture     /* Copy the CRC into place. */
140*de8a16e2SPatrick Venture     uint16_t crcValue = ipmiblob::generateCrc(crcBuffer);
141ef3aeadcSPatrick Venture     std::memcpy(replyCmdBuf, &crcValue, sizeof(crcValue));
142ef3aeadcSPatrick Venture 
143ef3aeadcSPatrick Venture     return result;
144ef3aeadcSPatrick Venture }
145ef3aeadcSPatrick Venture } // namespace blobs
146