xref: /openbmc/phosphor-ipmi-blobs/process.cpp (revision d1c3e86f2368ec69098a4e786a5c4e9d2455ae1d)
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>
22b15b3050SPatrick Venture #include <unordered_map>
23ef3aeadcSPatrick Venture #include <vector>
24ef3aeadcSPatrick Venture 
25ef3aeadcSPatrick Venture namespace blobs
26ef3aeadcSPatrick Venture {
27ef3aeadcSPatrick Venture 
28ef3aeadcSPatrick Venture /* Used by all commands with data. */
29ef3aeadcSPatrick Venture struct BmcRx
30ef3aeadcSPatrick Venture {
31ef3aeadcSPatrick Venture     uint8_t cmd;
32ef3aeadcSPatrick Venture     uint16_t crc;
33ef3aeadcSPatrick Venture     uint8_t data; /* one byte minimum of data. */
34ef3aeadcSPatrick Venture } __attribute__((packed));
35ef3aeadcSPatrick Venture 
36b15b3050SPatrick Venture static const std::unordered_map<BlobOEMCommands, IpmiBlobHandler> handlers = {
37b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobGetCount, getBlobCount},
38b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobEnumerate, enumerateBlob},
39b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobOpen, openBlob},
40b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobRead, readBlob},
41b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobWrite, writeBlob},
42b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobCommit, commitBlob},
43b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobClose, closeBlob},
44b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobDelete, deleteBlob},
45b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobStat, statBlob},
46b15b3050SPatrick Venture     {BlobOEMCommands::bmcBlobSessionStat, sessionStatBlob},
475c4b17b2SPatrick Venture     {BlobOEMCommands::bmcBlobWriteMeta, writeMeta},
48b15b3050SPatrick Venture };
49b15b3050SPatrick Venture 
50ef3aeadcSPatrick Venture IpmiBlobHandler validateBlobCommand(CrcInterface* crc, const uint8_t* reqBuf,
5141258800SPatrick Venture                                     uint8_t* replyCmdBuf, size_t* dataLen,
5241258800SPatrick Venture                                     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->clear();
92ef3aeadcSPatrick Venture         crc->compute(bytes.data(), bytes.size());
93ef3aeadcSPatrick Venture 
94ef3aeadcSPatrick Venture         /* Crc expected but didn't match. */
95ef3aeadcSPatrick Venture         if (crcValue != crc->get())
96ef3aeadcSPatrick Venture         {
9741258800SPatrick Venture             *code = IPMI_CC_UNSPECIFIED_ERROR;
98ef3aeadcSPatrick Venture             return nullptr;
99ef3aeadcSPatrick Venture         }
100ef3aeadcSPatrick Venture     }
101ef3aeadcSPatrick Venture 
102b15b3050SPatrick Venture     /* Grab the corresponding handler for the command. */
103b15b3050SPatrick Venture     auto found = handlers.find(command);
104b15b3050SPatrick Venture     if (found == handlers.end())
105ef3aeadcSPatrick Venture     {
10641258800SPatrick Venture         *code = IPMI_CC_INVALID_FIELD_REQUEST;
107ef3aeadcSPatrick Venture         return nullptr;
108ef3aeadcSPatrick Venture     }
109ef3aeadcSPatrick Venture 
110b15b3050SPatrick Venture     return found->second;
111ef3aeadcSPatrick Venture }
112ef3aeadcSPatrick Venture 
113ef3aeadcSPatrick Venture ipmi_ret_t processBlobCommand(IpmiBlobHandler cmd, ManagerInterface* mgr,
114ef3aeadcSPatrick Venture                               CrcInterface* crc, const uint8_t* reqBuf,
115ef3aeadcSPatrick Venture                               uint8_t* replyCmdBuf, size_t* dataLen)
116ef3aeadcSPatrick Venture {
117ef3aeadcSPatrick Venture     ipmi_ret_t result = cmd(mgr, reqBuf, replyCmdBuf, dataLen);
118ef3aeadcSPatrick Venture     if (result != IPMI_CC_OK)
119ef3aeadcSPatrick Venture     {
120ef3aeadcSPatrick Venture         return result;
121ef3aeadcSPatrick Venture     }
122ef3aeadcSPatrick Venture 
123ef3aeadcSPatrick Venture     size_t replyLength = (*dataLen);
124ef3aeadcSPatrick Venture 
125ef3aeadcSPatrick Venture     /* The command, whatever it was, returned success. */
126ef3aeadcSPatrick Venture     if (replyLength == 0)
127ef3aeadcSPatrick Venture     {
128ef3aeadcSPatrick Venture         return result;
129ef3aeadcSPatrick Venture     }
130ef3aeadcSPatrick Venture 
131*d1c3e86fSPatrick Venture     /* Read can return 0 bytes, and just a CRC, otherwise you need a CRC and 1
132*d1c3e86fSPatrick Venture      * byte, therefore the limit is 2 bytes.
133*d1c3e86fSPatrick Venture      */
134*d1c3e86fSPatrick Venture     if (replyLength < (sizeof(uint16_t)))
135ef3aeadcSPatrick Venture     {
13641258800SPatrick Venture         return IPMI_CC_UNSPECIFIED_ERROR;
137ef3aeadcSPatrick Venture     }
138ef3aeadcSPatrick Venture 
139ef3aeadcSPatrick Venture     /* The command, whatever it was, replied, so let's set the CRC. */
140ef3aeadcSPatrick Venture     crc->clear();
141ebf7b9b6SPatrick Venture     crc->compute(replyCmdBuf + sizeof(uint16_t),
142ebf7b9b6SPatrick Venture                  replyLength - sizeof(uint16_t));
143ef3aeadcSPatrick Venture 
144ef3aeadcSPatrick Venture     /* Copy the CRC into place. */
145ef3aeadcSPatrick Venture     uint16_t crcValue = crc->get();
146ef3aeadcSPatrick Venture     std::memcpy(replyCmdBuf, &crcValue, sizeof(crcValue));
147ef3aeadcSPatrick Venture 
148ef3aeadcSPatrick Venture     return result;
149ef3aeadcSPatrick Venture }
150ef3aeadcSPatrick Venture } // namespace blobs
151