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