1 #include "keyword_vpd_parser.hpp"
2 
3 #include "const.hpp"
4 
5 #include <iostream>
6 #include <numeric>
7 #include <string>
8 
9 using namespace openpower::vpd::constants;
10 using namespace openpower::vpd::inventory;
11 using namespace std;
12 using namespace openpower::vpd;
13 
14 namespace vpd
15 {
16 namespace keyword
17 {
18 namespace parser
19 {
20 
parse()21 variant<KeywordVpdMap, store> KeywordVpdParser::parse()
22 {
23     int kwVpdType;
24 
25     validateLargeResourceIdentifierString();
26 
27     kwVpdType = validateTheTypeOfKwVpd();
28 
29     auto kwValMap = kwValParser();
30 
31     // Do not process these two functions for bono type VPD
32     if (!kwVpdType)
33     {
34         validateSmallResourceTypeEnd();
35 
36         validateChecksum();
37     }
38 
39     validateSmallResourceTypeLastEnd();
40 
41 #ifdef DEBUG_KW_VPD
42     cerr << '\n' << " KW " << '\t' << "  VALUE " << '\n';
43     for (const auto& it : kwValMap)
44     {
45         cerr << '\n' << " " << it->first << '\t';
46         copy((it->second).begin(), (it->second).end(),
47              ostream_iterator<int>(cout << hex, " "));
48     }
49 #endif
50 
51     return kwValMap;
52 }
53 
validateLargeResourceIdentifierString()54 void KeywordVpdParser::validateLargeResourceIdentifierString()
55 {
56     kwVpdIterator = keywordVpdVector.begin();
57 
58     // Check for large resource type identifier string
59     if (*kwVpdIterator != KW_VPD_START_TAG)
60     {
61         throw std::runtime_error(
62             "Invalid Large resource type Identifier String");
63     }
64 
65     itrOutOfBoundCheck(1);
66     advance(kwVpdIterator, sizeof(KW_VPD_START_TAG));
67 }
68 
validateTheTypeOfKwVpd()69 int KeywordVpdParser::validateTheTypeOfKwVpd()
70 {
71     size_t dataSize = getKwDataSize();
72 
73     itrOutOfBoundCheck(TWO_BYTES + dataSize);
74 
75 #ifdef DEBUG_KW_VPD
76     auto dsDeb = dataSize;
77     auto itDeb = kwVpdIterator + TWO_BYTES;
78     std::cout << '\n' << '\t';
79     while (dsDeb != 0)
80     {
81         std::cout << *itDeb;
82         itDeb++;
83         dsDeb--;
84     }
85     std::cout << '\n';
86 #endif
87 
88     // +TWO_BYTES is the description's size byte
89     std::advance(kwVpdIterator, TWO_BYTES + dataSize);
90 
91     int kwVpdType = 0;
92     // Check for invalid vendor defined large resource type
93     if (*kwVpdIterator != KW_VAL_PAIR_START_TAG)
94     {
95         if (*kwVpdIterator != ALT_KW_VAL_PAIR_START_TAG)
96         {
97             throw std::runtime_error("Invalid Keyword Value Pair Start Tag");
98         }
99         // Bono vpd referred as 1
100         kwVpdType = 1;
101     }
102     return kwVpdType;
103 }
104 
kwValParser()105 KeywordVpdMap KeywordVpdParser::kwValParser()
106 {
107     int totalSize = 0;
108     KeywordVpdMap kwValMap;
109 
110     checkSumStart = kwVpdIterator;
111 
112     itrOutOfBoundCheck(1);
113     kwVpdIterator++;
114 
115     // Get the total length of all keyword value pairs
116     totalSize = getKwDataSize();
117 
118     if (totalSize == 0)
119     {
120         throw std::runtime_error("Badly formed keyword VPD data");
121     }
122 
123     itrOutOfBoundCheck(TWO_BYTES);
124     std::advance(kwVpdIterator, TWO_BYTES);
125 
126     // Parse the keyword-value and store the pairs in map
127     while (totalSize > 0)
128     {
129         std::string kwStr(kwVpdIterator, kwVpdIterator + TWO_BYTES);
130 
131         totalSize -= TWO_BYTES;
132         itrOutOfBoundCheck(TWO_BYTES);
133         std::advance(kwVpdIterator, TWO_BYTES);
134 
135         size_t kwSize = *kwVpdIterator;
136 
137         itrOutOfBoundCheck(1);
138         kwVpdIterator++;
139 
140         std::vector<uint8_t> valVec(kwVpdIterator, kwVpdIterator + kwSize);
141 
142         itrOutOfBoundCheck(kwSize);
143         std::advance(kwVpdIterator, kwSize);
144 
145         totalSize -= kwSize + 1;
146 
147         kwValMap.emplace(std::make_pair(std::move(kwStr), std::move(valVec)));
148     }
149 
150     checkSumEnd = kwVpdIterator - 1;
151 
152     return kwValMap;
153 }
154 
validateSmallResourceTypeEnd()155 void KeywordVpdParser::validateSmallResourceTypeEnd()
156 {
157     // Check for small resource type end tag
158     if (*kwVpdIterator != KW_VAL_PAIR_END_TAG)
159     {
160         throw std::runtime_error("Invalid Small resource type End");
161     }
162 }
163 
validateChecksum()164 void KeywordVpdParser::validateChecksum()
165 {
166     uint8_t checkSum = 0;
167 
168     // Checksum calculation
169     checkSum = std::accumulate(checkSumStart, checkSumEnd + 1, checkSum);
170     checkSum = ~checkSum + 1;
171 
172     if (checkSum != *(kwVpdIterator + 1))
173     {
174         throw std::runtime_error("Invalid Check sum");
175     }
176 #ifdef DEBUG_KW_VPD
177     std::cout << "\nCHECKSUM : " << std::hex << static_cast<int>(checkSum)
178               << std::endl;
179 #endif
180 
181     itrOutOfBoundCheck(TWO_BYTES);
182     std::advance(kwVpdIterator, TWO_BYTES);
183 }
184 
validateSmallResourceTypeLastEnd()185 void KeywordVpdParser::validateSmallResourceTypeLastEnd()
186 {
187     // Check for small resource type last end of data
188     if (*kwVpdIterator != KW_VPD_END_TAG)
189     {
190         throw std::runtime_error(
191             "Invalid Small resource type Last End Of Data");
192     }
193 }
194 
getKwDataSize()195 size_t KeywordVpdParser::getKwDataSize()
196 {
197     return (*(kwVpdIterator + 1) << 8 | *kwVpdIterator);
198 }
199 
itrOutOfBoundCheck(uint8_t incVar)200 void KeywordVpdParser::itrOutOfBoundCheck(uint8_t incVar)
201 {
202     if ((std::distance(keywordVpdVector.begin(), kwVpdIterator + incVar)) >
203         std::distance(keywordVpdVector.begin(), keywordVpdVector.end()))
204     {
205         throw std::runtime_error("Badly formed VPD data");
206     }
207 }
208 
getInterfaceName() const209 std::string KeywordVpdParser::getInterfaceName() const
210 {
211     return kwdVpdInf;
212 }
213 
214 } // namespace parser
215 } // namespace keyword
216 } // namespace vpd
217