blob: e5100e29c96d74030e0ba3b6a18b66f5f4e5ea52 [file] [log] [blame]
kasunathbac958d2022-06-07 18:15:24 -07001#include "rde/rde_handler.hpp"
2
3#include <fmt/format.h>
4
5#include <iostream>
6
7namespace bios_bmc_smm_error_logger
8{
9namespace rde
10{
11
12/**
13 * @brief CRC-32 divisor.
14 *
15 * This is equivalent to the one used by IEEE802.3.
16 */
17constexpr uint32_t crcDevisor = 0xedb88320;
18
19RdeCommandHandler::RdeCommandHandler(
20 std::unique_ptr<ExternalStorerInterface> exStorer) :
21 flagState(RdeDictTransferFlagState::RdeStateIdle),
22 exStorer(std::move(exStorer))
23{
24 // Initialize CRC table.
25 calcCrcTable();
26}
27
28RdeDecodeStatus
29 RdeCommandHandler::decodeRdeCommand(std::span<const uint8_t> rdeCommand,
30 RdeCommandType type)
31{
32 if (type == RdeCommandType::RdeMultiPartReceiveResponse)
33 {
34 return multiPartReceiveResp(rdeCommand);
35 }
36 if (type == RdeCommandType::RdeOperationInitRequest)
37 {
38 return operationInitRequest(rdeCommand);
39 }
40
41 fmt::print(stderr, "Invalid command type\n");
42 return RdeDecodeStatus::RdeInvalidCommand;
43}
44
45uint32_t RdeCommandHandler::getDictionaryCount()
46{
47 return dictionaryManager.getDictionaryCount();
48}
49
50RdeDecodeStatus
51 RdeCommandHandler::operationInitRequest(std::span<const uint8_t> rdeCommand)
52{
53 const RdeOperationInitReqHeader* header =
54 reinterpret_cast<const RdeOperationInitReqHeader*>(rdeCommand.data());
55 // Check if there is a payload. If not, we are not doing anything.
56 if (!header->containsRequestPayload)
57 {
58 return RdeDecodeStatus::RdeOk;
59 }
60
61 if (header->operationType != rdeOpInitOperationUpdate)
62 {
63 fmt::print(stderr, "Operation not supported\n");
64 return RdeDecodeStatus::RdeUnsupportedOperation;
65 }
66
67 // OperationInit payload overflows are not suported.
68 if (header->sendDataTransferHandle != 0)
69 {
70 fmt::print(stderr, "Payload should fit in within the request\n");
71 return RdeDecodeStatus::RdePayloadOverflow;
72 }
73
74 auto schemaDictOrErr = dictionaryManager.getDictionary(header->resourceID);
75 if (!schemaDictOrErr)
76 {
77 fmt::print(stderr, "Schema Dictionary not found for resourceId: {}\n",
78 header->resourceID);
79 return RdeDecodeStatus::RdeNoDictionary;
80 }
81
82 auto annotationDictOrErr = dictionaryManager.getAnnotationDictionary();
83 if (!annotationDictOrErr)
84 {
85 fmt::print(stderr, "Annotation dictionary not found\n");
86 return RdeDecodeStatus::RdeNoDictionary;
87 }
88
89 BejDictionaries dictionaries = {
90 .schemaDictionary = (*schemaDictOrErr).data(),
91 .annotationDictionary = (*annotationDictOrErr).data(),
92 // We do not use the error dictionary.
93 .errorDictionary = nullptr,
94 };
95
96 // Soon after header, we have bejLocator field. Then we have the encoded
97 // data.
98 const uint8_t* encodedPldmBlock = rdeCommand.data() +
99 sizeof(RdeOperationInitReqHeader) +
100 header->operationLocatorLength;
101
102 // Decoded the data.
103 if (decoder.decode(dictionaries, std::span(encodedPldmBlock,
104 header->requestPayloadLength)) !=
105 0)
106 {
107 fmt::print(stderr, "BEJ decoding failed.\n");
108 return RdeDecodeStatus::RdeBejDecodingError;
109 }
110
111 // Post the output.
112 if (!exStorer->publishJson(decoder.getOutput()))
113 {
114 fmt::print(stderr, "Failed to write to ExternalStorer.\n");
115 return RdeDecodeStatus::RdeExternalStorerError;
116 }
117 return RdeDecodeStatus::RdeOk;
118}
119
120RdeDecodeStatus
121 RdeCommandHandler::multiPartReceiveResp(std::span<const uint8_t> rdeCommand)
122{
123 const MultipartReceiveResHeader* header =
124 reinterpret_cast<const MultipartReceiveResHeader*>(rdeCommand.data());
125
126 // This is a hack to get the resource ID for the dictionary data. Even
127 // though nextDataTransferHandle field is supposed to be used for something
128 // else, BIOS is using it to specify the resource ID corresponding to the
129 // dictionary data.
130 uint32_t resourceId = header->nextDataTransferHandle;
131
132 // data points to the payload of the MultipartReceive.
133 const uint8_t* data = rdeCommand.data() + sizeof(MultipartReceiveResHeader);
134 RdeDecodeStatus ret = RdeDecodeStatus::RdeOk;
135
136 switch (header->transferFlag)
137 {
138 case rdeMRecFlagStart:
139 handleFlagStart(header, data, resourceId);
140 break;
141 case rdeMRecFlagMiddle:
142 ret = handleFlagMiddle(header, data, resourceId);
143 break;
144 case rdeMRecFlagEnd:
145 ret = handleFlagEnd(rdeCommand, header, data, resourceId);
146 break;
147 case rdeMRecFlagStartAndEnd:
148 ret = handleFlagStartAndEnd(rdeCommand, header, data, resourceId);
149 break;
150 default:
151 fmt::print(stderr, "Invalid transfer flag: {}\n",
152 header->transferFlag);
153 ret = RdeDecodeStatus::RdeInvalidCommand;
154 }
155
156 // If there is a failure, this assignment is not useful. So we can do it
157 // even if there is a failure.
158 prevDictResourceId = resourceId;
159 return ret;
160}
161
162void RdeCommandHandler::calcCrcTable()
163{
164 for (uint32_t i = 0; i < UINT8_MAX + 1; ++i)
165 {
166 uint32_t rem = i;
167 for (uint8_t k = 0; k < 8; ++k)
168 {
169 rem = (rem & 1) ? (rem >> 1) ^ crcDevisor : rem >> 1;
170 }
171 crcTable[i] = rem;
172 }
173}
174
175void RdeCommandHandler::updateCrc(std::span<const uint8_t> stream)
176{
177 for (uint32_t i = 0; i < stream.size_bytes(); ++i)
178 {
179 crc = crcTable[(crc ^ stream[i]) & 0xff] ^ (crc >> 8);
180 }
181}
182
183uint32_t RdeCommandHandler::finalChecksum()
184{
185 return (crc ^ 0xFFFFFFFF);
186}
187
188RdeDecodeStatus
189 RdeCommandHandler::handleCrc(std::span<const uint8_t> multiReceiveRespCmd)
190{
191 const MultipartReceiveResHeader* header =
192 reinterpret_cast<const MultipartReceiveResHeader*>(
193 multiReceiveRespCmd.data());
194 const uint8_t* checksumPtr = multiReceiveRespCmd.data() +
195 sizeof(MultipartReceiveResHeader) +
196 header->dataLengthBytes;
197 uint32_t checksum = checksumPtr[0] | (checksumPtr[1] << 8) |
198 (checksumPtr[2] << 16) | (checksumPtr[3] << 24);
199
200 if (finalChecksum() != checksum)
201 {
202 fmt::print(stderr, "Checksum failed. Ex: {} Calculated: {}\n", checksum,
203 finalChecksum());
204 dictionaryManager.invalidateDictionaries();
205 return RdeDecodeStatus::RdeInvalidChecksum;
206 }
207 return RdeDecodeStatus::RdeOk;
208}
209
210void RdeCommandHandler::handleFlagStart(const MultipartReceiveResHeader* header,
211 const uint8_t* data,
212 uint32_t resourceId)
213{
214 // This is a beginning of a dictionary. Reset CRC.
215 crc = 0xFFFFFFFF;
216 std::span dataS(data, header->dataLengthBytes);
217 dictionaryManager.startDictionaryEntry(resourceId, dataS);
218 // Start checksum calculation only for the data portion.
219 updateCrc(dataS);
220 flagState = RdeDictTransferFlagState::RdeStateStartRecvd;
221}
222
223RdeDecodeStatus
224 RdeCommandHandler::handleFlagMiddle(const MultipartReceiveResHeader* header,
225 const uint8_t* data,
226 uint32_t resourceId)
227{
228 if (flagState != RdeDictTransferFlagState::RdeStateStartRecvd)
229 {
230 fmt::print(
231 stderr,
232 "Invalid dictionary packet order. Need start before middle.\n");
233 return RdeDecodeStatus::RdeInvalidPktOrder;
234 }
235
236 std::span dataS(data, header->dataLengthBytes);
237 if (prevDictResourceId != resourceId)
238 {
239 // Start of a new dictionary. Mark previous dictionary as
240 // complete.
241 dictionaryManager.markDataComplete(prevDictResourceId);
242 dictionaryManager.startDictionaryEntry(resourceId, dataS);
243 }
244 else
245 {
246 // Not a new dictionary. Add the received data to the existing
247 // dictionary.
248 if (!dictionaryManager.addDictionaryData(resourceId, dataS))
249 {
250 fmt::print(stderr,
251 "Failed to add dictionary data: ResourceId: {}\n",
252 resourceId);
253 return RdeDecodeStatus::RdeDictionaryError;
254 }
255 }
256 // Continue checksum calculation only for the data portion.
257 updateCrc(dataS);
258 return RdeDecodeStatus::RdeOk;
259}
260
261RdeDecodeStatus
262 RdeCommandHandler::handleFlagEnd(std::span<const uint8_t> rdeCommand,
263 const MultipartReceiveResHeader* header,
264 const uint8_t* data, uint32_t resourceId)
265{
266 if (flagState != RdeDictTransferFlagState::RdeStateStartRecvd)
267 {
268 fmt::print(
269 stderr,
270 "Invalid dictionary packet order. Need start before middle.\n");
271 return RdeDecodeStatus::RdeInvalidPktOrder;
272 }
273 flagState = RdeDictTransferFlagState::RdeStateIdle;
274
275 std::span dataS(data, header->dataLengthBytes);
276 if (prevDictResourceId != resourceId)
277 {
278 // Start of a new dictionary. Mark previous dictionary as
279 // complete.
280 dictionaryManager.markDataComplete(prevDictResourceId);
281 dictionaryManager.startDictionaryEntry(resourceId, dataS);
282 }
283 else
284 {
285 if (!dictionaryManager.addDictionaryData(resourceId, dataS))
286 {
287 fmt::print(stderr,
288 "Failed to add dictionary data: ResourceId: {}\n",
289 resourceId);
290 return RdeDecodeStatus::RdeDictionaryError;
291 }
292 }
293 dictionaryManager.markDataComplete(resourceId);
294
295 // Continue checksum calculation only for the data portion. At the end of
296 // data, we will have the DataIntegrityChecksum field. So omit that when
297 // calculating checksum.
298 updateCrc(dataS);
299 auto ret = handleCrc(rdeCommand);
300 if (ret != RdeDecodeStatus::RdeOk)
301 {
302 return ret;
303 }
304 return RdeDecodeStatus::RdeStopFlagReceived;
305}
306
307RdeDecodeStatus RdeCommandHandler::handleFlagStartAndEnd(
308 std::span<const uint8_t> rdeCommand,
309 const MultipartReceiveResHeader* header, const uint8_t* data,
310 uint32_t resourceId)
311{
312 // This is a beginning of a dictionary. Reset CRC.
313 crc = 0xFFFFFFFF;
314 // This is a beginning and end of a dictionary.
315 dictionaryManager.startDictionaryEntry(
316 resourceId, std::span(data, header->dataLengthBytes));
317 dictionaryManager.markDataComplete(resourceId);
318 flagState = RdeDictTransferFlagState::RdeStateIdle;
319
320 // Do checksum calculation only for the data portion. At the end of data, we
321 // will have the DataIntegrityChecksum field. So omit that when calculating
322 // checksum.
323 updateCrc(std::span(data, header->dataLengthBytes));
324
325 auto ret = handleCrc(rdeCommand);
326 if (ret != RdeDecodeStatus::RdeOk)
327 {
328 return ret;
329 }
330 return RdeDecodeStatus::RdeStopFlagReceived;
331}
332
333} // namespace rde
334} // namespace bios_bmc_smm_error_logger