xref: /openbmc/pldm/platform-mc/terminus.cpp (revision 6b901e4a78338605c27c477f2a254dd3c3c38c72)
1 #include "terminus.hpp"
2 
3 #include "libpldm/platform.h"
4 
5 #include "terminus_manager.hpp"
6 
7 #include <ranges>
8 
9 namespace pldm
10 {
11 namespace platform_mc
12 {
13 
14 Terminus::Terminus(pldm_tid_t tid, uint64_t supportedTypes) :
15     initialized(false), tid(tid), supportedTypes(supportedTypes)
16 {}
17 
18 bool Terminus::doesSupportType(uint8_t type)
19 {
20     return supportedTypes.test(type);
21 }
22 
23 bool Terminus::doesSupportCommand(uint8_t type, uint8_t command)
24 {
25     if (!doesSupportType(type))
26     {
27         return false;
28     }
29 
30     try
31     {
32         const size_t idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + (command / 8);
33         if (idx >= supportedCmds.size())
34         {
35             return false;
36         }
37 
38         if (supportedCmds[idx] & (1 << (command % 8)))
39         {
40             lg2::info(
41                 "PLDM type {TYPE} command {CMD} is supported by terminus {TID}",
42                 "TYPE", type, "CMD", command, "TID", getTid());
43             return true;
44         }
45     }
46     catch (const std::exception& e)
47     {
48         return false;
49     }
50 
51     return false;
52 }
53 
54 void Terminus::parseTerminusPDRs()
55 {
56     std::vector<std::shared_ptr<pldm_numeric_sensor_value_pdr>>
57         numericSensorPdrs{};
58     std::vector<std::shared_ptr<pldm_compact_numeric_sensor_pdr>>
59         compactNumericSensorPdrs{};
60 
61     for (auto& pdr : pdrs)
62     {
63         auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
64         switch (pdrHdr->type)
65         {
66             case PLDM_SENSOR_AUXILIARY_NAMES_PDR:
67             {
68                 auto sensorAuxNames = parseSensorAuxiliaryNamesPDR(pdr);
69                 if (!sensorAuxNames)
70                 {
71                     lg2::error(
72                         "Failed to parse PDR with type {TYPE} handle {HANDLE}",
73                         "TYPE", pdrHdr->type, "HANDLE",
74                         static_cast<uint32_t>(pdrHdr->record_handle));
75                     continue;
76                 }
77                 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
78                 break;
79             }
80             case PLDM_NUMERIC_SENSOR_PDR:
81             {
82                 auto parsedPdr = parseNumericSensorPDR(pdr);
83                 if (!parsedPdr)
84                 {
85                     lg2::error(
86                         "Failed to parse PDR with type {TYPE} handle {HANDLE}",
87                         "TYPE", pdrHdr->type, "HANDLE",
88                         static_cast<uint32_t>(pdrHdr->record_handle));
89                     continue;
90                 }
91                 numericSensorPdrs.emplace_back(std::move(parsedPdr));
92                 break;
93             }
94             case PLDM_COMPACT_NUMERIC_SENSOR_PDR:
95             {
96                 auto parsedPdr = parseCompactNumericSensorPDR(pdr);
97                 if (!parsedPdr)
98                 {
99                     lg2::error(
100                         "Failed to parse PDR with type {TYPE} handle {HANDLE}",
101                         "TYPE", pdrHdr->type, "HANDLE",
102                         static_cast<uint32_t>(pdrHdr->record_handle));
103                     continue;
104                 }
105                 auto sensorAuxNames = parseCompactNumericSensorNames(pdr);
106                 if (!sensorAuxNames)
107                 {
108                     lg2::error(
109                         "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}",
110                         "TYPE", pdrHdr->type, "HANDLE",
111                         static_cast<uint32_t>(pdrHdr->record_handle));
112                     continue;
113                 }
114                 compactNumericSensorPdrs.emplace_back(std::move(parsedPdr));
115                 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
116                 break;
117             }
118             default:
119             {
120                 lg2::error("Unsupported PDR with type {TYPE} handle {HANDLE}",
121                            "TYPE", pdrHdr->type, "HANDLE",
122                            static_cast<uint32_t>(pdrHdr->record_handle));
123                 break;
124             }
125         }
126     }
127 }
128 
129 std::shared_ptr<SensorAuxiliaryNames>
130     Terminus::getSensorAuxiliaryNames(SensorId id)
131 {
132     auto it = std::find_if(
133         sensorAuxiliaryNamesTbl.begin(), sensorAuxiliaryNamesTbl.end(),
134         [id](
135             const std::shared_ptr<SensorAuxiliaryNames>& sensorAuxiliaryNames) {
136         const auto& [sensorId, sensorCnt, sensorNames] = *sensorAuxiliaryNames;
137         return sensorId == id;
138     });
139 
140     if (it != sensorAuxiliaryNamesTbl.end())
141     {
142         return *it;
143     }
144     return nullptr;
145 };
146 
147 std::shared_ptr<SensorAuxiliaryNames>
148     Terminus::parseSensorAuxiliaryNamesPDR(const std::vector<uint8_t>& pdrData)
149 {
150     constexpr uint8_t nullTerminator = 0;
151     auto pdr = reinterpret_cast<const struct pldm_sensor_auxiliary_names_pdr*>(
152         pdrData.data());
153     const uint8_t* ptr = pdr->names;
154     std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>>
155         sensorAuxNames{};
156     char16_t alignedBuffer[PLDM_STR_UTF_16_MAX_LEN];
157     for ([[maybe_unused]] const auto& sensor :
158          std::views::iota(0, static_cast<int>(pdr->sensor_count)))
159     {
160         const uint8_t nameStringCount = static_cast<uint8_t>(*ptr);
161         ptr += sizeof(uint8_t);
162         std::vector<std::pair<NameLanguageTag, SensorName>> nameStrings{};
163         for ([[maybe_unused]] const auto& count :
164              std::views::iota(0, static_cast<int>(nameStringCount)))
165         {
166             std::string_view nameLanguageTag(
167                 reinterpret_cast<const char*>(ptr));
168             ptr += nameLanguageTag.size() + sizeof(nullTerminator);
169 
170             int u16NameStringLen = 0;
171             for (int i = 0; ptr[i] != 0 || ptr[i + 1] != 0; i += 2)
172             {
173                 u16NameStringLen++;
174             }
175             /* include terminator */
176             u16NameStringLen++;
177 
178             std::fill(std::begin(alignedBuffer), std::end(alignedBuffer), 0);
179             if (u16NameStringLen > PLDM_STR_UTF_16_MAX_LEN)
180             {
181                 lg2::error("Sensor name to long.");
182                 return nullptr;
183             }
184             memcpy(alignedBuffer, ptr, u16NameStringLen * sizeof(uint16_t));
185             std::u16string u16NameString(alignedBuffer, u16NameStringLen);
186             ptr += (u16NameString.size() + sizeof(nullTerminator)) *
187                    sizeof(uint16_t);
188             std::transform(u16NameString.cbegin(), u16NameString.cend(),
189                            u16NameString.begin(),
190                            [](uint16_t utf16) { return be16toh(utf16); });
191             std::string nameString =
192                 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,
193                                      char16_t>{}
194                     .to_bytes(u16NameString);
195             std::replace(nameString.begin(), nameString.end(), ' ', '_');
196             auto nullTerminatorPos = nameString.find('\0');
197             if (nullTerminatorPos != std::string::npos)
198             {
199                 nameString.erase(nullTerminatorPos);
200             }
201             nameStrings.emplace_back(
202                 std::make_pair(nameLanguageTag, nameString));
203         }
204         sensorAuxNames.emplace_back(std::move(nameStrings));
205     }
206     return std::make_shared<SensorAuxiliaryNames>(
207         pdr->sensor_id, pdr->sensor_count, std::move(sensorAuxNames));
208 }
209 
210 std::shared_ptr<pldm_numeric_sensor_value_pdr>
211     Terminus::parseNumericSensorPDR(const std::vector<uint8_t>& pdr)
212 {
213     const uint8_t* ptr = pdr.data();
214     auto parsedPdr = std::make_shared<pldm_numeric_sensor_value_pdr>();
215     auto rc = decode_numeric_sensor_pdr_data(ptr, pdr.size(), parsedPdr.get());
216     if (rc)
217     {
218         return nullptr;
219     }
220     return parsedPdr;
221 }
222 
223 std::shared_ptr<SensorAuxiliaryNames>
224     Terminus::parseCompactNumericSensorNames(const std::vector<uint8_t>& sPdr)
225 {
226     std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>>
227         sensorAuxNames{};
228     std::vector<std::pair<NameLanguageTag, SensorName>> nameStrings{};
229     auto pdr =
230         reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
231 
232     if (sPdr.size() <
233         (sizeof(pldm_compact_numeric_sensor_pdr) - sizeof(uint8_t)))
234     {
235         return nullptr;
236     }
237 
238     if (!pdr->sensor_name_length ||
239         (sPdr.size() < (sizeof(pldm_compact_numeric_sensor_pdr) -
240                         sizeof(uint8_t) + pdr->sensor_name_length)))
241     {
242         return nullptr;
243     }
244 
245     std::string nameString(reinterpret_cast<const char*>(pdr->sensor_name),
246                            pdr->sensor_name_length);
247     std::replace(nameString.begin(), nameString.end(), ' ', '_');
248     auto nullTerminatorPos = nameString.find('\0');
249     if (nullTerminatorPos != std::string::npos)
250     {
251         nameString.erase(nullTerminatorPos);
252     }
253     nameStrings.emplace_back(std::make_pair("en", nameString));
254     sensorAuxNames.emplace_back(std::move(nameStrings));
255 
256     return std::make_shared<SensorAuxiliaryNames>(pdr->sensor_id, 1,
257                                                   std::move(sensorAuxNames));
258 }
259 
260 std::shared_ptr<pldm_compact_numeric_sensor_pdr>
261     Terminus::parseCompactNumericSensorPDR(const std::vector<uint8_t>& sPdr)
262 {
263     auto pdr =
264         reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
265     if (sPdr.size() < sizeof(pldm_compact_numeric_sensor_pdr))
266     {
267         // Handle error: input data too small to contain valid pdr
268         return nullptr;
269     }
270     auto parsedPdr = std::make_shared<pldm_compact_numeric_sensor_pdr>();
271 
272     parsedPdr->hdr = pdr->hdr;
273     parsedPdr->terminus_handle = pdr->terminus_handle;
274     parsedPdr->sensor_id = pdr->sensor_id;
275     parsedPdr->entity_type = pdr->entity_type;
276     parsedPdr->entity_instance = pdr->entity_instance;
277     parsedPdr->container_id = pdr->container_id;
278     parsedPdr->sensor_name_length = pdr->sensor_name_length;
279     parsedPdr->base_unit = pdr->base_unit;
280     parsedPdr->unit_modifier = pdr->unit_modifier;
281     parsedPdr->occurrence_rate = pdr->occurrence_rate;
282     parsedPdr->range_field_support = pdr->range_field_support;
283     parsedPdr->warning_high = pdr->warning_high;
284     parsedPdr->warning_low = pdr->warning_low;
285     parsedPdr->critical_high = pdr->critical_high;
286     parsedPdr->critical_low = pdr->critical_low;
287     parsedPdr->fatal_high = pdr->fatal_high;
288     parsedPdr->fatal_low = pdr->fatal_low;
289     return parsedPdr;
290 }
291 
292 } // namespace platform_mc
293 } // namespace pldm
294