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