xref: /openbmc/phosphor-ipmi-blobs/process.cpp (revision b15b3050600f0201cd0fa81b88af270bb2720de5)
1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "process.hpp"
18 
19 #include "ipmi.hpp"
20 
21 #include <cstring>
22 #include <unordered_map>
23 #include <vector>
24 
25 namespace blobs
26 {
27 
28 /* Used by all commands with data. */
29 struct BmcRx
30 {
31     uint8_t cmd;
32     uint16_t crc;
33     uint8_t data; /* one byte minimum of data. */
34 } __attribute__((packed));
35 
36 static const std::unordered_map<BlobOEMCommands, IpmiBlobHandler> handlers = {
37     {BlobOEMCommands::bmcBlobGetCount, getBlobCount},
38     {BlobOEMCommands::bmcBlobEnumerate, enumerateBlob},
39     {BlobOEMCommands::bmcBlobOpen, openBlob},
40     {BlobOEMCommands::bmcBlobRead, readBlob},
41     {BlobOEMCommands::bmcBlobWrite, writeBlob},
42     {BlobOEMCommands::bmcBlobCommit, commitBlob},
43     {BlobOEMCommands::bmcBlobClose, closeBlob},
44     {BlobOEMCommands::bmcBlobDelete, deleteBlob},
45     {BlobOEMCommands::bmcBlobStat, statBlob},
46     {BlobOEMCommands::bmcBlobSessionStat, sessionStatBlob},
47 };
48 
49 IpmiBlobHandler validateBlobCommand(CrcInterface* crc, const uint8_t* reqBuf,
50                                     uint8_t* replyCmdBuf, size_t* dataLen)
51 {
52     size_t requestLength = (*dataLen);
53     /* We know dataLen is at least 1 already */
54     auto command = static_cast<BlobOEMCommands>(reqBuf[0]);
55 
56     /* Validate it's at least well-formed. */
57     if (!validateRequestLength(command, requestLength))
58     {
59         return nullptr;
60     }
61 
62     /* If there is a payload. */
63     if (requestLength > sizeof(uint8_t))
64     {
65         /* Verify the request includes: command, crc16, data */
66         if (requestLength < sizeof(struct BmcRx))
67         {
68             return nullptr;
69         }
70 
71         /* We don't include the command byte at offset 0 as part of the crc
72          * payload area or the crc bytes at the beginning.
73          */
74         size_t requestBodyLen = requestLength - 3;
75 
76         /* We start after the command byte. */
77         std::vector<uint8_t> bytes(requestBodyLen);
78 
79         /* It likely has a well-formed payload. */
80         struct BmcRx request;
81         std::memcpy(&request, reqBuf, sizeof(request));
82         uint16_t crcValue = request.crc;
83 
84         /* Set the in-place CRC to zero. */
85         std::memcpy(bytes.data(), &reqBuf[3], requestBodyLen);
86 
87         crc->clear();
88         crc->compute(bytes.data(), bytes.size());
89 
90         /* Crc expected but didn't match. */
91         if (crcValue != crc->get())
92         {
93             return nullptr;
94         }
95     }
96 
97     /* Grab the corresponding handler for the command. */
98     auto found = handlers.find(command);
99     if (found == handlers.end())
100     {
101         return nullptr;
102     }
103 
104     return found->second;
105 }
106 
107 ipmi_ret_t processBlobCommand(IpmiBlobHandler cmd, ManagerInterface* mgr,
108                               CrcInterface* crc, const uint8_t* reqBuf,
109                               uint8_t* replyCmdBuf, size_t* dataLen)
110 {
111     ipmi_ret_t result = cmd(mgr, reqBuf, replyCmdBuf, dataLen);
112     if (result != IPMI_CC_OK)
113     {
114         return result;
115     }
116 
117     size_t replyLength = (*dataLen);
118 
119     /* The command, whatever it was, returned success. */
120     if (replyLength == 0)
121     {
122         return result;
123     }
124 
125     /* The response, if it has one byte, has three, to include the crc16. */
126     if (replyLength < (sizeof(uint16_t) + 1))
127     {
128         return IPMI_CC_INVALID;
129     }
130 
131     /* The command, whatever it was, replied, so let's set the CRC. */
132     crc->clear();
133     replyCmdBuf[0] = 0x00;
134     replyCmdBuf[1] = 0x00;
135     crc->compute(replyCmdBuf, replyLength);
136 
137     /* Copy the CRC into place. */
138     uint16_t crcValue = crc->get();
139     std::memcpy(replyCmdBuf, &crcValue, sizeof(crcValue));
140 
141     return result;
142 }
143 } // namespace blobs
144