1 #include "terminus.hpp" 2 3 #include "libpldm/platform.h" 4 5 #include "terminus_manager.hpp" 6 7 #include <common/utils.hpp> 8 9 #include <ranges> 10 11 namespace pldm 12 { 13 namespace platform_mc 14 { 15 16 Terminus::Terminus(pldm_tid_t tid, uint64_t supportedTypes) : 17 initialized(false), tid(tid), supportedTypes(supportedTypes) 18 {} 19 20 bool Terminus::doesSupportType(uint8_t type) 21 { 22 return supportedTypes.test(type); 23 } 24 25 bool 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 56 std::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 85 void 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 } 149 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 } 163 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 } 172 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 } 180 } 181 182 std::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 200 std::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; 207 std::vector<AuxiliaryNames> sensorAuxNames{}; 208 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); 214 AuxiliaryNames nameStrings{}; 215 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); 247 nameStrings.emplace_back(std::make_pair( 248 nameLanguageTag, pldm::utils::trimNameForDbus(nameString))); 249 } 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 256 std::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 319 std::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 332 std::shared_ptr<SensorAuxiliaryNames> 333 Terminus::parseCompactNumericSensorNames(const std::vector<uint8_t>& sPdr) 334 { 335 std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>> 336 sensorAuxNames{}; 337 AuxiliaryNames nameStrings{}; 338 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); 356 nameStrings.emplace_back( 357 std::make_pair("en", pldm::utils::trimNameForDbus(nameString))); 358 sensorAuxNames.emplace_back(std::move(nameStrings)); 359 360 return std::make_shared<SensorAuxiliaryNames>(pdr->sensor_id, 1, 361 std::move(sensorAuxNames)); 362 } 363 364 std::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 396 } // namespace platform_mc 397 } // namespace pldm 398