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 <vector>
23 
24 namespace blobs
25 {
26 
27 /* Used by all commands with data. */
28 struct BmcRx
29 {
30     uint8_t cmd;
31     uint16_t crc;
32     uint8_t data; /* one byte minimum of data. */
33 } __attribute__((packed));
34 
35 IpmiBlobHandler validateBlobCommand(CrcInterface* crc, const uint8_t* reqBuf,
36                                     uint8_t* replyCmdBuf, size_t* dataLen)
37 {
38     IpmiBlobHandler cmd;
39     size_t requestLength = (*dataLen);
40     /* We know dataLen is at least 1 already */
41     auto command = static_cast<BlobOEMCommands>(reqBuf[0]);
42 
43     /* Validate it's at least well-formed. */
44     if (!validateRequestLength(command, requestLength))
45     {
46         return nullptr;
47     }
48 
49     /* If there is a payload. */
50     if (requestLength > sizeof(uint8_t))
51     {
52         /* Verify the request includes: command, crc16, data */
53         if (requestLength < sizeof(struct BmcRx))
54         {
55             return nullptr;
56         }
57 
58         /* We don't include the command byte at offset 0 as part of the crc
59          * payload area or the crc bytes at the beginning.
60          */
61         size_t requestBodyLen = requestLength - 3;
62 
63         /* We start after the command byte. */
64         std::vector<uint8_t> bytes(requestBodyLen);
65 
66         /* It likely has a well-formed payload. */
67         struct BmcRx request;
68         std::memcpy(&request, reqBuf, sizeof(request));
69         uint16_t crcValue = request.crc;
70 
71         /* Set the in-place CRC to zero. */
72         std::memcpy(bytes.data(), &reqBuf[3], requestBodyLen);
73 
74         crc->clear();
75         crc->compute(bytes.data(), bytes.size());
76 
77         /* Crc expected but didn't match. */
78         if (crcValue != crc->get())
79         {
80             return nullptr;
81         }
82     }
83 
84     /* Grab the corresponding handler for the command (could do map or array
85      * of function pointer lookup).
86      */
87     switch (command)
88     {
89         case BlobOEMCommands::bmcBlobGetCount:
90             cmd = getBlobCount;
91             break;
92         case BlobOEMCommands::bmcBlobEnumerate:
93             cmd = enumerateBlob;
94             break;
95         case BlobOEMCommands::bmcBlobOpen:
96             cmd = openBlob;
97             break;
98         case BlobOEMCommands::bmcBlobRead:
99             cmd = readBlob;
100             break;
101         case BlobOEMCommands::bmcBlobWrite:
102             cmd = writeBlob;
103             break;
104         case BlobOEMCommands::bmcBlobCommit:
105             cmd = commitBlob;
106             break;
107         case BlobOEMCommands::bmcBlobClose:
108             cmd = closeBlob;
109             break;
110         case BlobOEMCommands::bmcBlobDelete:
111             cmd = deleteBlob;
112             break;
113         case BlobOEMCommands::bmcBlobStat:
114             cmd = statBlob;
115             break;
116         case BlobOEMCommands::bmcBlobSessionStat:
117             cmd = sessionStatBlob;
118             break;
119         default:
120             return nullptr;
121     }
122 
123     return cmd;
124 }
125 
126 ipmi_ret_t processBlobCommand(IpmiBlobHandler cmd, ManagerInterface* mgr,
127                               CrcInterface* crc, const uint8_t* reqBuf,
128                               uint8_t* replyCmdBuf, size_t* dataLen)
129 {
130     ipmi_ret_t result = cmd(mgr, reqBuf, replyCmdBuf, dataLen);
131     if (result != IPMI_CC_OK)
132     {
133         return result;
134     }
135 
136     size_t replyLength = (*dataLen);
137 
138     /* The command, whatever it was, returned success. */
139     if (replyLength == 0)
140     {
141         return result;
142     }
143 
144     /* The response, if it has one byte, has three, to include the crc16. */
145     if (replyLength < (sizeof(uint16_t) + 1))
146     {
147         return IPMI_CC_INVALID;
148     }
149 
150     /* The command, whatever it was, replied, so let's set the CRC. */
151     crc->clear();
152     replyCmdBuf[0] = 0x00;
153     replyCmdBuf[1] = 0x00;
154     crc->compute(replyCmdBuf, replyLength);
155 
156     /* Copy the CRC into place. */
157     uint16_t crcValue = crc->get();
158     std::memcpy(replyCmdBuf, &crcValue, sizeof(crcValue));
159 
160     return result;
161 }
162 } // namespace blobs
163