blob: 2892dc1c033c19d8d43eb5723fa12bc727f939ba [file] [log] [blame]
Gilbert Chen6c7fed42022-02-22 15:40:17 +00001#include "terminus.hpp"
2
3#include "libpldm/platform.h"
4
5#include "terminus_manager.hpp"
6
Thu Nguyenb8cf46b2024-06-15 02:44:35 +00007#include <common/utils.hpp>
8
Gilbert Chende2a1322022-05-24 15:35:21 +01009#include <ranges>
10
Gilbert Chen6c7fed42022-02-22 15:40:17 +000011namespace pldm
12{
13namespace platform_mc
14{
15
16Terminus::Terminus(pldm_tid_t tid, uint64_t supportedTypes) :
17 initialized(false), tid(tid), supportedTypes(supportedTypes)
18{}
19
20bool Terminus::doesSupportType(uint8_t type)
21{
22 return supportedTypes.test(type);
23}
24
25bool Terminus::doesSupportCommand(uint8_t type, uint8_t command)
26{
27 if (!doesSupportType(type))
28 {
29 return false;
30 }
31
32 try
33 {
34 const size_t idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + (command / 8);
35 if (idx >= supportedCmds.size())
36 {
37 return false;
38 }
39
40 if (supportedCmds[idx] & (1 << (command % 8)))
41 {
42 lg2::info(
43 "PLDM type {TYPE} command {CMD} is supported by terminus {TID}",
44 "TYPE", type, "CMD", command, "TID", getTid());
45 return true;
46 }
47 }
48 catch (const std::exception& e)
49 {
50 return false;
51 }
52
53 return false;
54}
55
Thu Nguyenb8cf46b2024-06-15 02:44:35 +000056std::optional<std::string_view> Terminus::findTerminusName()
57{
58 auto it = std::find_if(
59 entityAuxiliaryNamesTbl.begin(), entityAuxiliaryNamesTbl.end(),
60 [](const std::shared_ptr<EntityAuxiliaryNames>& entityAuxiliaryNames) {
61 const auto& [key, entityNames] = *entityAuxiliaryNames;
62 /**
63 * There is only one Overal system container entity in one terminus.
64 * The entity auxiliary name PDR of that terminus with the that type of
65 * containerID will include terminus name.
66 **/
67 return (entityAuxiliaryNames &&
68 key.containerId == PLDM_PLATFORM_ENTITY_SYSTEM_CONTAINER_ID &&
69 entityNames.size());
70 });
71
72 if (it != entityAuxiliaryNamesTbl.end())
73 {
74 const auto& [key, entityNames] = **it;
75 if (!entityNames.size())
76 {
77 return std::nullopt;
78 }
79 return entityNames[0].second;
80 }
81
82 return std::nullopt;
83}
84
Gilbert Chende2a1322022-05-24 15:35:21 +010085void Terminus::parseTerminusPDRs()
86{
87 std::vector<std::shared_ptr<pldm_numeric_sensor_value_pdr>>
88 numericSensorPdrs{};
89 std::vector<std::shared_ptr<pldm_compact_numeric_sensor_pdr>>
90 compactNumericSensorPdrs{};
91
92 for (auto& pdr : pdrs)
93 {
94 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
95 switch (pdrHdr->type)
96 {
97 case PLDM_SENSOR_AUXILIARY_NAMES_PDR:
98 {
99 auto sensorAuxNames = parseSensorAuxiliaryNamesPDR(pdr);
100 if (!sensorAuxNames)
101 {
102 lg2::error(
103 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
104 "TYPE", pdrHdr->type, "HANDLE",
105 static_cast<uint32_t>(pdrHdr->record_handle));
106 continue;
107 }
108 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
109 break;
110 }
111 case PLDM_NUMERIC_SENSOR_PDR:
112 {
113 auto parsedPdr = parseNumericSensorPDR(pdr);
114 if (!parsedPdr)
115 {
116 lg2::error(
117 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
118 "TYPE", pdrHdr->type, "HANDLE",
119 static_cast<uint32_t>(pdrHdr->record_handle));
120 continue;
121 }
122 numericSensorPdrs.emplace_back(std::move(parsedPdr));
123 break;
124 }
125 case PLDM_COMPACT_NUMERIC_SENSOR_PDR:
126 {
127 auto parsedPdr = parseCompactNumericSensorPDR(pdr);
128 if (!parsedPdr)
129 {
130 lg2::error(
131 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
132 "TYPE", pdrHdr->type, "HANDLE",
133 static_cast<uint32_t>(pdrHdr->record_handle));
134 continue;
135 }
136 auto sensorAuxNames = parseCompactNumericSensorNames(pdr);
137 if (!sensorAuxNames)
138 {
139 lg2::error(
140 "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}",
141 "TYPE", pdrHdr->type, "HANDLE",
142 static_cast<uint32_t>(pdrHdr->record_handle));
143 continue;
144 }
145 compactNumericSensorPdrs.emplace_back(std::move(parsedPdr));
146 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
147 break;
148 }
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000149 case PLDM_ENTITY_AUXILIARY_NAMES_PDR:
150 {
151 auto entityNames = parseEntityAuxiliaryNamesPDR(pdr);
152 if (!entityNames)
153 {
154 lg2::error(
155 "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}",
156 "TYPE", pdrHdr->type, "HANDLE",
157 static_cast<uint32_t>(pdrHdr->record_handle));
158 continue;
159 }
160 entityAuxiliaryNamesTbl.emplace_back(std::move(entityNames));
161 break;
162 }
Gilbert Chende2a1322022-05-24 15:35:21 +0100163 default:
164 {
165 lg2::error("Unsupported PDR with type {TYPE} handle {HANDLE}",
166 "TYPE", pdrHdr->type, "HANDLE",
167 static_cast<uint32_t>(pdrHdr->record_handle));
168 break;
169 }
170 }
171 }
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000172
173 auto tName = findTerminusName();
174 if (tName && !tName.value().empty())
175 {
176 lg2::info("Terminus {TID} has Auxiliary Name {NAME}.", "TID", tid,
177 "NAME", tName.value());
178 terminusName = static_cast<std::string>(tName.value());
179 }
Gilbert Chende2a1322022-05-24 15:35:21 +0100180}
181
182std::shared_ptr<SensorAuxiliaryNames>
183 Terminus::getSensorAuxiliaryNames(SensorId id)
184{
185 auto it = std::find_if(
186 sensorAuxiliaryNamesTbl.begin(), sensorAuxiliaryNamesTbl.end(),
187 [id](
188 const std::shared_ptr<SensorAuxiliaryNames>& sensorAuxiliaryNames) {
189 const auto& [sensorId, sensorCnt, sensorNames] = *sensorAuxiliaryNames;
190 return sensorId == id;
191 });
192
193 if (it != sensorAuxiliaryNamesTbl.end())
194 {
195 return *it;
196 }
197 return nullptr;
198};
199
200std::shared_ptr<SensorAuxiliaryNames>
201 Terminus::parseSensorAuxiliaryNamesPDR(const std::vector<uint8_t>& pdrData)
202{
203 constexpr uint8_t nullTerminator = 0;
204 auto pdr = reinterpret_cast<const struct pldm_sensor_auxiliary_names_pdr*>(
205 pdrData.data());
206 const uint8_t* ptr = pdr->names;
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000207 std::vector<AuxiliaryNames> sensorAuxNames{};
Gilbert Chende2a1322022-05-24 15:35:21 +0100208 char16_t alignedBuffer[PLDM_STR_UTF_16_MAX_LEN];
209 for ([[maybe_unused]] const auto& sensor :
210 std::views::iota(0, static_cast<int>(pdr->sensor_count)))
211 {
212 const uint8_t nameStringCount = static_cast<uint8_t>(*ptr);
213 ptr += sizeof(uint8_t);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000214 AuxiliaryNames nameStrings{};
Gilbert Chende2a1322022-05-24 15:35:21 +0100215 for ([[maybe_unused]] const auto& count :
216 std::views::iota(0, static_cast<int>(nameStringCount)))
217 {
218 std::string_view nameLanguageTag(
219 reinterpret_cast<const char*>(ptr));
220 ptr += nameLanguageTag.size() + sizeof(nullTerminator);
221
222 int u16NameStringLen = 0;
223 for (int i = 0; ptr[i] != 0 || ptr[i + 1] != 0; i += 2)
224 {
225 u16NameStringLen++;
226 }
227 /* include terminator */
228 u16NameStringLen++;
229
230 std::fill(std::begin(alignedBuffer), std::end(alignedBuffer), 0);
231 if (u16NameStringLen > PLDM_STR_UTF_16_MAX_LEN)
232 {
233 lg2::error("Sensor name to long.");
234 return nullptr;
235 }
236 memcpy(alignedBuffer, ptr, u16NameStringLen * sizeof(uint16_t));
237 std::u16string u16NameString(alignedBuffer, u16NameStringLen);
238 ptr += (u16NameString.size() + sizeof(nullTerminator)) *
239 sizeof(uint16_t);
240 std::transform(u16NameString.cbegin(), u16NameString.cend(),
241 u16NameString.begin(),
242 [](uint16_t utf16) { return be16toh(utf16); });
243 std::string nameString =
244 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,
245 char16_t>{}
246 .to_bytes(u16NameString);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000247 nameStrings.emplace_back(std::make_pair(
248 nameLanguageTag, pldm::utils::trimNameForDbus(nameString)));
Gilbert Chende2a1322022-05-24 15:35:21 +0100249 }
250 sensorAuxNames.emplace_back(std::move(nameStrings));
251 }
252 return std::make_shared<SensorAuxiliaryNames>(
253 pdr->sensor_id, pdr->sensor_count, std::move(sensorAuxNames));
254}
255
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000256std::shared_ptr<EntityAuxiliaryNames>
257 Terminus::parseEntityAuxiliaryNamesPDR(const std::vector<uint8_t>& pdrData)
258{
259 auto names_offset = sizeof(struct pldm_pdr_hdr) +
260 PLDM_PDR_ENTITY_AUXILIARY_NAME_PDR_MIN_LENGTH;
261 auto names_size = pdrData.size() - names_offset;
262
263 size_t decodedPdrSize = sizeof(struct pldm_entity_auxiliary_names_pdr) +
264 names_size;
265 auto vPdr = std::vector<char>(decodedPdrSize);
266 auto decodedPdr =
267 reinterpret_cast<struct pldm_entity_auxiliary_names_pdr*>(vPdr.data());
268
269 auto rc = decode_entity_auxiliary_names_pdr(pdrData.data(), pdrData.size(),
270 decodedPdr, decodedPdrSize);
271
272 if (rc)
273 {
274 lg2::error(
275 "Failed to decode Entity Auxiliary Name PDR data, error {RC}.",
276 "RC", rc);
277 return nullptr;
278 }
279
280 auto vNames =
281 std::vector<pldm_entity_auxiliary_name>(decodedPdr->name_string_count);
282 decodedPdr->names = vNames.data();
283
284 rc = decode_pldm_entity_auxiliary_names_pdr_index(decodedPdr);
285 if (rc)
286 {
287 lg2::error("Failed to decode Entity Auxiliary Name, error {RC}.", "RC",
288 rc);
289 return nullptr;
290 }
291
292 AuxiliaryNames nameStrings{};
293 for (const auto& count :
294 std::views::iota(0, static_cast<int>(decodedPdr->name_string_count)))
295 {
296 std::string_view nameLanguageTag =
297 static_cast<std::string_view>(decodedPdr->names[count].tag);
298 const size_t u16NameStringLen =
299 std::char_traits<char16_t>::length(decodedPdr->names[count].name);
300 std::u16string u16NameString(decodedPdr->names[count].name,
301 u16NameStringLen);
302 std::transform(u16NameString.cbegin(), u16NameString.cend(),
303 u16NameString.begin(),
304 [](uint16_t utf16) { return be16toh(utf16); });
305 std::string nameString =
306 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}
307 .to_bytes(u16NameString);
308 nameStrings.emplace_back(std::make_pair(
309 nameLanguageTag, pldm::utils::trimNameForDbus(nameString)));
310 }
311
312 EntityKey key{decodedPdr->container.entity_type,
313 decodedPdr->container.entity_instance_num,
314 decodedPdr->container.entity_container_id};
315
316 return std::make_shared<EntityAuxiliaryNames>(key, nameStrings);
317}
318
Gilbert Chende2a1322022-05-24 15:35:21 +0100319std::shared_ptr<pldm_numeric_sensor_value_pdr>
320 Terminus::parseNumericSensorPDR(const std::vector<uint8_t>& pdr)
321{
322 const uint8_t* ptr = pdr.data();
323 auto parsedPdr = std::make_shared<pldm_numeric_sensor_value_pdr>();
324 auto rc = decode_numeric_sensor_pdr_data(ptr, pdr.size(), parsedPdr.get());
325 if (rc)
326 {
327 return nullptr;
328 }
329 return parsedPdr;
330}
331
332std::shared_ptr<SensorAuxiliaryNames>
333 Terminus::parseCompactNumericSensorNames(const std::vector<uint8_t>& sPdr)
334{
335 std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>>
336 sensorAuxNames{};
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000337 AuxiliaryNames nameStrings{};
Gilbert Chende2a1322022-05-24 15:35:21 +0100338 auto pdr =
339 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
340
341 if (sPdr.size() <
342 (sizeof(pldm_compact_numeric_sensor_pdr) - sizeof(uint8_t)))
343 {
344 return nullptr;
345 }
346
347 if (!pdr->sensor_name_length ||
348 (sPdr.size() < (sizeof(pldm_compact_numeric_sensor_pdr) -
349 sizeof(uint8_t) + pdr->sensor_name_length)))
350 {
351 return nullptr;
352 }
353
354 std::string nameString(reinterpret_cast<const char*>(pdr->sensor_name),
355 pdr->sensor_name_length);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000356 nameStrings.emplace_back(
357 std::make_pair("en", pldm::utils::trimNameForDbus(nameString)));
Gilbert Chende2a1322022-05-24 15:35:21 +0100358 sensorAuxNames.emplace_back(std::move(nameStrings));
359
360 return std::make_shared<SensorAuxiliaryNames>(pdr->sensor_id, 1,
361 std::move(sensorAuxNames));
362}
363
364std::shared_ptr<pldm_compact_numeric_sensor_pdr>
365 Terminus::parseCompactNumericSensorPDR(const std::vector<uint8_t>& sPdr)
366{
367 auto pdr =
368 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
369 if (sPdr.size() < sizeof(pldm_compact_numeric_sensor_pdr))
370 {
371 // Handle error: input data too small to contain valid pdr
372 return nullptr;
373 }
374 auto parsedPdr = std::make_shared<pldm_compact_numeric_sensor_pdr>();
375
376 parsedPdr->hdr = pdr->hdr;
377 parsedPdr->terminus_handle = pdr->terminus_handle;
378 parsedPdr->sensor_id = pdr->sensor_id;
379 parsedPdr->entity_type = pdr->entity_type;
380 parsedPdr->entity_instance = pdr->entity_instance;
381 parsedPdr->container_id = pdr->container_id;
382 parsedPdr->sensor_name_length = pdr->sensor_name_length;
383 parsedPdr->base_unit = pdr->base_unit;
384 parsedPdr->unit_modifier = pdr->unit_modifier;
385 parsedPdr->occurrence_rate = pdr->occurrence_rate;
386 parsedPdr->range_field_support = pdr->range_field_support;
387 parsedPdr->warning_high = pdr->warning_high;
388 parsedPdr->warning_low = pdr->warning_low;
389 parsedPdr->critical_high = pdr->critical_high;
390 parsedPdr->critical_low = pdr->critical_low;
391 parsedPdr->fatal_high = pdr->fatal_high;
392 parsedPdr->fatal_low = pdr->fatal_low;
393 return parsedPdr;
394}
395
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000396} // namespace platform_mc
397} // namespace pldm