FruDevice: additional diagnostics when decode FRU
FruDevice currently has kind of loyal policy for FRU decoding, so one
can have a broken FRU but doesn't notice it.
This adds more diagnostics when decode FRU binary.
Tested: 1) tested with several different good FRUs
2) tested with modified FRU like:
* wrong checksum in data area
* no C1 in the end of area
* change one of C0 to C1
Signed-off-by: Andrei Kartashev <a.kartashev@yadro.com>
Change-Id: Id703dada73eb1fa35abd531a3303b06288bd4aad
diff --git a/src/FruDevice.cpp b/src/FruDevice.cpp
index b92116e..b2072e6 100644
--- a/src/FruDevice.cpp
+++ b/src/FruDevice.cpp
@@ -129,6 +129,8 @@
return FRU_AREA_NAMES[static_cast<unsigned int>(area)];
}
bool validateHeader(const std::array<uint8_t, I2C_SMBUS_BLOCK_MAX>& blockData);
+uint8_t calculateChecksum(std::vector<uint8_t>::const_iterator iter,
+ std::vector<uint8_t>::const_iterator end);
bool updateFRUProperty(
const std::string& assetTag, uint32_t bus, uint32_t address,
std::string propertyName,
@@ -966,6 +968,17 @@
return make_pair(DecodeState::ok, value);
}
+static void checkLang(uint8_t lang)
+{
+ // If Lang is not English then the encoding is defined as 2-byte UNICODE,
+ // but we don't support that.
+ if (lang && lang != 25)
+ {
+ std::cerr << "Warning: language other then English is not "
+ "supported \n";
+ }
+}
+
bool formatFRU(const std::vector<uint8_t>& fruBytes,
boost::container::flat_map<std::string, std::string>& result)
{
@@ -1009,6 +1022,14 @@
fruBytes.begin() + offset + fruAreaSize - 1;
++fruBytesIter;
+ if (calculateChecksum(fruBytes.begin() + offset, fruBytesIterEndArea) !=
+ *fruBytesIterEndArea)
+ {
+ std::cerr << "Checksum error in FRU area " << getFruAreaName(area)
+ << "\n";
+ return false;
+ }
+
switch (area)
{
case fruAreas::fruAreaChassis:
@@ -1021,8 +1042,10 @@
}
case fruAreas::fruAreaBoard:
{
+ uint8_t lang = *fruBytesIter;
result["BOARD_LANGUAGE_CODE"] =
- std::to_string(static_cast<int>(*fruBytesIter));
+ std::to_string(static_cast<int>(lang));
+ checkLang(lang);
fruBytesIter += 1;
unsigned int minutes = *fruBytesIter |
@@ -1050,8 +1073,10 @@
}
case fruAreas::fruAreaProduct:
{
+ uint8_t lang = *fruBytesIter;
result["PRODUCT_LANGUAGE_CODE"] =
- std::to_string(static_cast<int>(*fruBytesIter));
+ std::to_string(static_cast<int>(lang));
+ checkLang(lang);
fruBytesIter += 1;
fruAreaFieldNames = &PRODUCT_FRU_AREAS;
break;
@@ -1106,7 +1131,26 @@
return false;
}
}
+ else
+ {
+ if (fieldIndex < fruAreaFieldNames->size())
+ {
+ std::cerr << "Mandatory fields absent in FRU area "
+ << getFruAreaName(area) << " after " << name
+ << "\n";
+ }
+ }
} while (state == DecodeState::ok);
+ for (; fruBytesIter < fruBytesIterEndArea; fruBytesIter++)
+ {
+ uint8_t c = *fruBytesIter;
+ if (c)
+ {
+ std::cerr << "Non-zero byte after EndOfFields in FRU area "
+ << getFruAreaName(area) << "\n";
+ break;
+ }
+ }
}
return true;
@@ -1530,12 +1574,18 @@
}
// Calculate new checksum for fru info area
-size_t calculateChecksum(std::vector<uint8_t>& fruAreaData)
+uint8_t calculateChecksum(std::vector<uint8_t>::const_iterator iter,
+ std::vector<uint8_t>::const_iterator end)
{
constexpr int checksumMod = 256;
constexpr uint8_t modVal = 0xFF;
- int sum = std::accumulate(fruAreaData.begin(), fruAreaData.end(), 0);
- return (checksumMod - sum) & modVal;
+ int sum = std::accumulate(iter, end, 0);
+ int checksum = (checksumMod - sum) & modVal;
+ return static_cast<uint8_t>(checksum);
+}
+uint8_t calculateChecksum(std::vector<uint8_t>& fruAreaData)
+{
+ return calculateChecksum(fruAreaData.begin(), fruAreaData.end());
}
// Update new fru area length &
@@ -1575,9 +1625,7 @@
std::copy_n(fruData.begin() + fruAreaStart, checksumLoc - fruAreaStart,
std::back_inserter(finalFRUData));
- size_t checksumVal = calculateChecksum(finalFRUData);
-
- fruData[checksumLoc] = static_cast<uint8_t>(checksumVal);
+ fruData[checksumLoc] = calculateChecksum(finalFRUData);
return checksumLoc;
}