xref: /openbmc/openpower-vpd-parser/vpd-manager/src/keyword_vpd_parser.cpp (revision fa5e4d325ef9cea3c841fe89d202c340f92bd8c6)
1 #include "keyword_vpd_parser.hpp"
2 
3 #include "constants.hpp"
4 #include "exceptions.hpp"
5 #include "logger.hpp"
6 
7 #include <iostream>
8 #include <numeric>
9 #include <string>
10 
11 namespace vpd
12 {
13 
parse()14 types::VPDMapVariant KeywordVpdParser::parse()
15 {
16     if (m_keywordVpdVector.empty())
17     {
18         throw(DataException("Vector for Keyword format VPD is empty"));
19     }
20     m_vpdIterator = m_keywordVpdVector.begin();
21 
22     if (*m_vpdIterator != constants::KW_VPD_START_TAG)
23     {
24         throw(DataException("Invalid Large resource type Identifier String"));
25     }
26 
27     checkNextBytesValidity(sizeof(constants::KW_VPD_START_TAG));
28     std::advance(m_vpdIterator, sizeof(constants::KW_VPD_START_TAG));
29 
30     uint16_t l_dataSize = getKwDataSize();
31 
32     checkNextBytesValidity(constants::TWO_BYTES + l_dataSize);
33     std::advance(m_vpdIterator, constants::TWO_BYTES + l_dataSize);
34 
35     // Check for invalid vendor defined large resource type
36     if (*m_vpdIterator != constants::KW_VPD_PAIR_START_TAG)
37     {
38         if (*m_vpdIterator != constants::ALT_KW_VPD_PAIR_START_TAG)
39         {
40             throw(DataException("Invalid Keyword Vpd Start Tag"));
41         }
42     }
43     types::BinaryVector::const_iterator l_checkSumStart = m_vpdIterator;
44     auto l_kwValMap = populateVpdMap();
45 
46     // Do these validations before returning parsed data.
47     // Check for small resource type end tag
48     if (*m_vpdIterator != constants::KW_VAL_PAIR_END_TAG)
49     {
50         throw(DataException("Invalid Small resource type End"));
51     }
52 
53     types::BinaryVector::const_iterator l_checkSumEnd = m_vpdIterator;
54     validateChecksum(l_checkSumStart, l_checkSumEnd);
55 
56     checkNextBytesValidity(constants::TWO_BYTES);
57     std::advance(m_vpdIterator, constants::TWO_BYTES);
58 
59     // Check VPD end Tag.
60     if (*m_vpdIterator != constants::KW_VPD_END_TAG)
61     {
62         throw(DataException("Invalid Small resource type."));
63     }
64 
65     return l_kwValMap;
66 }
67 
populateVpdMap()68 types::KeywordVpdMap KeywordVpdParser::populateVpdMap()
69 {
70     checkNextBytesValidity(constants::ONE_BYTE);
71     std::advance(m_vpdIterator, constants::ONE_BYTE);
72 
73     auto l_totalSize = getKwDataSize();
74     if (l_totalSize == 0)
75     {
76         throw(DataException("Data size is 0, badly formed keyword VPD"));
77     }
78 
79     checkNextBytesValidity(constants::TWO_BYTES);
80     std::advance(m_vpdIterator, constants::TWO_BYTES);
81 
82     types::KeywordVpdMap l_kwValMap;
83 
84     // Parse the keyword-value and store the pairs in map
85     while (l_totalSize > 0)
86     {
87         checkNextBytesValidity(constants::TWO_BYTES);
88         std::string l_keywordName(m_vpdIterator,
89                                   m_vpdIterator + constants::TWO_BYTES);
90         std::advance(m_vpdIterator, constants::TWO_BYTES);
91 
92         size_t l_kwSize = *m_vpdIterator;
93         checkNextBytesValidity(constants::ONE_BYTE + l_kwSize);
94         m_vpdIterator++;
95         std::vector<uint8_t> l_valueBytes(m_vpdIterator,
96                                           m_vpdIterator + l_kwSize);
97         std::advance(m_vpdIterator, l_kwSize);
98 
99         l_kwValMap.emplace(
100             std::make_pair(std::move(l_keywordName), std::move(l_valueBytes)));
101 
102         l_totalSize -= constants::TWO_BYTES + constants::ONE_BYTE + l_kwSize;
103     }
104 
105     return l_kwValMap;
106 }
107 
validateChecksum(types::BinaryVector::const_iterator i_checkSumStart,types::BinaryVector::const_iterator i_checkSumEnd)108 void KeywordVpdParser::validateChecksum(
109     types::BinaryVector::const_iterator i_checkSumStart,
110     types::BinaryVector::const_iterator i_checkSumEnd)
111 {
112     uint8_t l_checkSumCalculated = 0;
113 
114     // Checksum calculation
115     l_checkSumCalculated =
116         std::accumulate(i_checkSumStart, i_checkSumEnd, l_checkSumCalculated);
117     l_checkSumCalculated = ~l_checkSumCalculated + 1;
118     uint8_t l_checksumVpdValue = *(m_vpdIterator + constants::ONE_BYTE);
119 
120     if (l_checkSumCalculated != l_checksumVpdValue)
121     {
122         throw(DataException("Invalid Checksum"));
123     }
124 }
125 
checkNextBytesValidity(uint8_t i_numberOfBytes)126 void KeywordVpdParser::checkNextBytesValidity(uint8_t i_numberOfBytes)
127 {
128     if ((std::distance(m_keywordVpdVector.begin(),
129                        m_vpdIterator + i_numberOfBytes)) >
130         std::distance(m_keywordVpdVector.begin(), m_keywordVpdVector.end()))
131     {
132         throw(DataException("Truncated VPD data"));
133     }
134 }
135 
136 } // namespace vpd
137