1 2 #include "platform.hpp" 3 4 #include "common/utils.hpp" 5 #include "event_parser.hpp" 6 #include "pdr_numeric_effecter.hpp" 7 #include "pdr_state_effecter.hpp" 8 #include "platform_numeric_effecter.hpp" 9 #include "platform_state_effecter.hpp" 10 11 namespace pldm 12 { 13 namespace responder 14 { 15 namespace platform 16 { 17 18 using InternalFailure = 19 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 20 21 static const Json empty{}; 22 23 using EventEntryMap = std::map<EventEntry, DBusInfo>; 24 25 const EventEntryMap eventEntryMap = { 26 { 27 0x01010007, // SensorID for VMI Port 0 ipv4 = 7, SensorOffset for the 28 // State Set ID 15 = 1 & PLDM State Set Enumeration List = 1 29 // (Valid Configuration) 30 {"/xyz/openbmc_project/network/vmi/intf0/ipv4/addr0", 31 "xyz.openbmc_project.Object.Enable", "Enabled", "bool", true}, 32 }, 33 { 34 0x02010007, // SensorID for VMI Port 0 ipv4 = 7, SensorOffset for the 35 // State Set ID 15 = 1 & PLDM State Set Enumeration List = 2 36 // (Invalid Configuration) 37 {"/xyz/openbmc_project/network/vmi/intf0/ipv4/addr0", 38 "xyz.openbmc_project.Object.Enable", "Enabled", "bool", false}, 39 }, 40 { 41 0x01010008, // SensorID for VMI Port 1 ipv4 = 8, SensorOffset for the 42 // State Set ID 15 = 1 & PLDM State Set Enumeration List = 1 43 // (Valid Configuration) 44 {"/xyz/openbmc_project/network/vmi/intf1/ipv4/addr0", 45 "xyz.openbmc_project.Object.Enable", "Enabled", "bool", true}, 46 }, 47 { 48 0x02010008, // SensorID for VMI Port 1 ipv4 = 8, SensorOffset for the 49 // State Set ID 15 = 1 & PLDM State Set Enumeration List = 2 50 // (Invalid Configuration) 51 {"/xyz/openbmc_project/network/vmi/intf1/ipv4/addr0", 52 "xyz.openbmc_project.Object.Enable", "Enabled", "bool", false}, 53 }}; 54 55 void Handler::addDbusObjMaps( 56 uint16_t effecterId, 57 std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> dbusObj) 58 { 59 dbusObjMaps.emplace(effecterId, dbusObj); 60 } 61 62 const std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>& 63 Handler::getDbusObjMaps(uint16_t effecterId) const 64 { 65 return dbusObjMaps.at(effecterId); 66 } 67 68 void Handler::generate(const std::string& dir, Repo& repo) 69 { 70 // A map of PDR type to a lambda that handles creation of that PDR type. 71 // The lambda essentially would parse the platform specific PDR JSONs to 72 // generate the PDR structures. This function iterates through the map to 73 // invoke all lambdas, so that all PDR types can be created. 74 75 const std::map<Type, generatePDR> generateHandlers = { 76 {PLDM_STATE_EFFECTER_PDR, 77 [this](const auto& json, RepoInterface& repo) { 78 pdr_state_effecter::generateStateEffecterPDR<Handler>(json, *this, 79 repo); 80 }}, 81 {PLDM_NUMERIC_EFFECTER_PDR, 82 [this](const auto& json, RepoInterface& repo) { 83 pdr_numeric_effecter::generateNumericEffecterPDR<Handler>( 84 json, *this, repo); 85 }}}; 86 87 Type pdrType{}; 88 for (const auto& dirEntry : fs::directory_iterator(dir)) 89 { 90 try 91 { 92 auto json = readJson(dirEntry.path().string()); 93 if (!json.empty()) 94 { 95 auto effecterPDRs = json.value("effecterPDRs", empty); 96 for (const auto& effecter : effecterPDRs) 97 { 98 pdrType = effecter.value("pdrType", 0); 99 generateHandlers.at(pdrType)(effecter, repo); 100 } 101 } 102 } 103 catch (const InternalFailure& e) 104 { 105 std::cerr << "PDR config directory does not exist or empty, TYPE= " 106 << pdrType << "PATH= " << dirEntry 107 << " ERROR=" << e.what() << "\n"; 108 } 109 catch (const Json::exception& e) 110 { 111 std::cerr << "Failed parsing PDR JSON file, TYPE= " << pdrType 112 << " ERROR=" << e.what() << "\n"; 113 pldm::utils::reportError( 114 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 115 } 116 catch (const std::exception& e) 117 { 118 std::cerr << "Failed parsing PDR JSON file, TYPE= " << pdrType 119 << " ERROR=" << e.what() << "\n"; 120 pldm::utils::reportError( 121 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 122 } 123 } 124 } 125 126 Response Handler::getPDR(const pldm_msg* request, size_t payloadLength) 127 { 128 // Build FRU table if not built, since entity association PDR's are built 129 // when the FRU table is constructed. 130 if (fruHandler) 131 { 132 fruHandler->buildFRUTable(); 133 } 134 135 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES, 0); 136 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 137 138 if (payloadLength != PLDM_GET_PDR_REQ_BYTES) 139 { 140 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 141 } 142 143 uint32_t recordHandle{}; 144 uint32_t dataTransferHandle{}; 145 uint8_t transferOpFlag{}; 146 uint16_t reqSizeBytes{}; 147 uint16_t recordChangeNum{}; 148 149 auto rc = decode_get_pdr_req(request, payloadLength, &recordHandle, 150 &dataTransferHandle, &transferOpFlag, 151 &reqSizeBytes, &recordChangeNum); 152 if (rc != PLDM_SUCCESS) 153 { 154 return CmdHandler::ccOnlyResponse(request, rc); 155 } 156 157 uint16_t respSizeBytes{}; 158 uint8_t* recordData = nullptr; 159 try 160 { 161 pdr_utils::PdrEntry e; 162 auto record = pdr::getRecordByHandle(pdrRepo, recordHandle, e); 163 if (record == NULL) 164 { 165 return CmdHandler::ccOnlyResponse( 166 request, PLDM_PLATFORM_INVALID_RECORD_HANDLE); 167 } 168 169 if (reqSizeBytes) 170 { 171 respSizeBytes = e.size; 172 if (respSizeBytes > reqSizeBytes) 173 { 174 respSizeBytes = reqSizeBytes; 175 } 176 recordData = e.data; 177 } 178 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES + 179 respSizeBytes, 180 0); 181 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 182 rc = encode_get_pdr_resp( 183 request->hdr.instance_id, PLDM_SUCCESS, e.handle.nextRecordHandle, 184 0, PLDM_START_AND_END, respSizeBytes, recordData, 0, responsePtr); 185 if (rc != PLDM_SUCCESS) 186 { 187 return ccOnlyResponse(request, rc); 188 } 189 } 190 catch (const std::exception& e) 191 { 192 std::cerr << "Error accessing PDR, HANDLE=" << recordHandle 193 << " ERROR=" << e.what() << "\n"; 194 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR); 195 } 196 return response; 197 } 198 199 Response Handler::setStateEffecterStates(const pldm_msg* request, 200 size_t payloadLength) 201 { 202 Response response( 203 sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES, 0); 204 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 205 uint16_t effecterId; 206 uint8_t compEffecterCnt; 207 constexpr auto maxCompositeEffecterCnt = 8; 208 std::vector<set_effecter_state_field> stateField(maxCompositeEffecterCnt, 209 {0, 0}); 210 211 if ((payloadLength > PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES) || 212 (payloadLength < sizeof(effecterId) + sizeof(compEffecterCnt) + 213 sizeof(set_effecter_state_field))) 214 { 215 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 216 } 217 218 int rc = decode_set_state_effecter_states_req(request, payloadLength, 219 &effecterId, &compEffecterCnt, 220 stateField.data()); 221 222 if (rc != PLDM_SUCCESS) 223 { 224 return CmdHandler::ccOnlyResponse(request, rc); 225 } 226 227 stateField.resize(compEffecterCnt); 228 const pldm::utils::DBusHandler dBusIntf; 229 rc = platform_state_effecter::setStateEffecterStatesHandler< 230 pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId, 231 stateField); 232 if (rc != PLDM_SUCCESS) 233 { 234 return CmdHandler::ccOnlyResponse(request, rc); 235 } 236 237 rc = encode_set_state_effecter_states_resp(request->hdr.instance_id, rc, 238 responsePtr); 239 if (rc != PLDM_SUCCESS) 240 { 241 return ccOnlyResponse(request, rc); 242 } 243 244 return response; 245 } 246 247 Response Handler::platformEventMessage(const pldm_msg* request, 248 size_t payloadLength) 249 { 250 uint8_t formatVersion{}; 251 uint8_t tid{}; 252 uint8_t eventClass{}; 253 size_t offset{}; 254 255 auto rc = decode_platform_event_message_req( 256 request, payloadLength, &formatVersion, &tid, &eventClass, &offset); 257 if (rc != PLDM_SUCCESS) 258 { 259 return CmdHandler::ccOnlyResponse(request, rc); 260 } 261 262 try 263 { 264 const auto& handlers = eventHandlers.at(eventClass); 265 for (const auto& handler : handlers) 266 { 267 auto rc = 268 handler(request, payloadLength, formatVersion, tid, offset); 269 if (rc != PLDM_SUCCESS) 270 { 271 return CmdHandler::ccOnlyResponse(request, rc); 272 } 273 } 274 } 275 catch (const std::out_of_range& e) 276 { 277 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_DATA); 278 } 279 280 Response response( 281 sizeof(pldm_msg_hdr) + PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES, 0); 282 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 283 284 rc = encode_platform_event_message_resp(request->hdr.instance_id, rc, 285 PLDM_EVENT_NO_LOGGING, responsePtr); 286 if (rc != PLDM_SUCCESS) 287 { 288 return ccOnlyResponse(request, rc); 289 } 290 291 return response; 292 } 293 294 int Handler::sensorEvent(const pldm_msg* request, size_t payloadLength, 295 uint8_t /*formatVersion*/, uint8_t tid, 296 size_t eventDataOffset) 297 { 298 uint16_t sensorId{}; 299 uint8_t eventClass{}; 300 size_t eventClassDataOffset{}; 301 auto eventData = 302 reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset; 303 auto eventDataSize = payloadLength - eventDataOffset; 304 305 auto rc = decode_sensor_event_data(eventData, eventDataSize, &sensorId, 306 &eventClass, &eventClassDataOffset); 307 if (rc != PLDM_SUCCESS) 308 { 309 return rc; 310 } 311 312 auto eventClassData = reinterpret_cast<const uint8_t*>(request->payload) + 313 eventDataOffset + eventClassDataOffset; 314 auto eventClassDataSize = 315 payloadLength - eventDataOffset - eventClassDataOffset; 316 317 if (eventClass == PLDM_STATE_SENSOR_STATE) 318 { 319 uint8_t sensorOffset{}; 320 uint8_t eventState{}; 321 uint8_t previousEventState{}; 322 323 rc = decode_state_sensor_data(eventClassData, eventClassDataSize, 324 &sensorOffset, &eventState, 325 &previousEventState); 326 if (rc != PLDM_SUCCESS) 327 { 328 return PLDM_ERROR; 329 } 330 331 // Handle PLDM events for which PDR is not available, setSensorEventData 332 // will return PLDM_ERROR_INVALID_DATA if the sensorID is not found in 333 // the hardcoded sensor list. 334 rc = setSensorEventData(sensorId, sensorOffset, eventState); 335 if (rc != PLDM_ERROR_INVALID_DATA) 336 { 337 return rc; 338 } 339 340 // If there are no HOST PDR's, there is no further action 341 if (hostPDRHandler == NULL) 342 { 343 return PLDM_SUCCESS; 344 } 345 346 // Handle PLDM events for which PDR is available 347 SensorEntry sensorEntry{tid, sensorId}; 348 try 349 { 350 const auto& [entityInfo, compositeSensorStates] = 351 hostPDRHandler->lookupSensorInfo(sensorEntry); 352 if (sensorOffset >= compositeSensorStates.size()) 353 { 354 return PLDM_ERROR_INVALID_DATA; 355 } 356 357 const auto& possibleStates = compositeSensorStates[sensorOffset]; 358 if (possibleStates.find(eventState) == possibleStates.end()) 359 { 360 return PLDM_ERROR_INVALID_DATA; 361 } 362 363 const auto& [containerId, entityType, entityInstance] = entityInfo; 364 events::StateSensorEntry stateSensorEntry{ 365 containerId, entityType, entityInstance, sensorOffset}; 366 return stateSensorHandler.eventAction(stateSensorEntry, eventState); 367 } 368 // If there is no mapping for events return PLDM_SUCCESS 369 catch (const std::out_of_range& e) 370 { 371 return PLDM_SUCCESS; 372 } 373 } 374 else 375 { 376 return PLDM_ERROR_INVALID_DATA; 377 } 378 379 return PLDM_SUCCESS; 380 } 381 382 int Handler::setSensorEventData(uint16_t sensorId, uint8_t sensorOffset, 383 uint8_t eventState) 384 { 385 EventEntry eventEntry = ((static_cast<uint32_t>(eventState)) << 24) + 386 ((static_cast<uint32_t>(sensorOffset)) << 16) + 387 sensorId; 388 auto iter = eventEntryMap.find(eventEntry); 389 if (iter == eventEntryMap.end()) 390 { 391 return PLDM_ERROR_INVALID_DATA; 392 } 393 394 const auto& dBusInfo = iter->second; 395 try 396 { 397 pldm::utils::DBusMapping dbusMapping{ 398 dBusInfo.dBusValues.objectPath, dBusInfo.dBusValues.interface, 399 dBusInfo.dBusValues.propertyName, dBusInfo.dBusValues.propertyType}; 400 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, 401 dBusInfo.dBusPropertyValue); 402 } 403 catch (std::exception& e) 404 { 405 std::cerr 406 << "Error Setting dbus property,SensorID=" << eventEntry 407 << "DBusInfo=" << dBusInfo.dBusValues.objectPath 408 << dBusInfo.dBusValues.interface << dBusInfo.dBusValues.propertyName 409 << "ERROR=" << e.what() << "\n"; 410 return PLDM_ERROR; 411 } 412 return PLDM_SUCCESS; 413 } 414 415 int Handler::pldmPDRRepositoryChgEvent(const pldm_msg* request, 416 size_t payloadLength, 417 uint8_t /*formatVersion*/, 418 uint8_t /*tid*/, size_t eventDataOffset) 419 { 420 uint8_t eventDataFormat{}; 421 uint8_t numberOfChangeRecords{}; 422 size_t dataOffset{}; 423 424 auto eventData = 425 reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset; 426 auto eventDataSize = payloadLength - eventDataOffset; 427 428 auto rc = decode_pldm_pdr_repository_chg_event_data( 429 eventData, eventDataSize, &eventDataFormat, &numberOfChangeRecords, 430 &dataOffset); 431 if (rc != PLDM_SUCCESS) 432 { 433 return rc; 434 } 435 436 PDRRecordHandles pdrRecordHandles; 437 if (eventDataFormat == FORMAT_IS_PDR_HANDLES) 438 { 439 uint8_t eventDataOperation{}; 440 uint8_t numberOfChangeEntries{}; 441 442 auto changeRecordData = eventData + dataOffset; 443 auto changeRecordDataSize = eventDataSize - dataOffset; 444 445 while (changeRecordDataSize) 446 { 447 rc = decode_pldm_pdr_repository_change_record_data( 448 changeRecordData, changeRecordDataSize, &eventDataOperation, 449 &numberOfChangeEntries, &dataOffset); 450 451 if (rc != PLDM_SUCCESS) 452 { 453 return rc; 454 } 455 456 if (eventDataOperation == PLDM_RECORDS_ADDED) 457 { 458 rc = getPDRRecordHandles( 459 reinterpret_cast<const ChangeEntry*>(changeRecordData + 460 dataOffset), 461 changeRecordDataSize - dataOffset, 462 static_cast<size_t>(numberOfChangeEntries), 463 pdrRecordHandles); 464 465 if (rc != PLDM_SUCCESS) 466 { 467 return rc; 468 } 469 } 470 471 changeRecordData += 472 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry)); 473 changeRecordDataSize -= 474 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry)); 475 } 476 477 if (hostPDRHandler && !pdrRecordHandles.empty()) 478 { 479 hostPDRHandler->fetchPDR(std::move(pdrRecordHandles)); 480 } 481 } 482 else 483 { 484 return PLDM_ERROR_INVALID_DATA; 485 } 486 487 return PLDM_SUCCESS; 488 } 489 490 int Handler::getPDRRecordHandles(const ChangeEntry* changeEntryData, 491 size_t changeEntryDataSize, 492 size_t numberOfChangeEntries, 493 PDRRecordHandles& pdrRecordHandles) 494 { 495 if (numberOfChangeEntries > (changeEntryDataSize / sizeof(ChangeEntry))) 496 { 497 return PLDM_ERROR_INVALID_DATA; 498 } 499 for (size_t i = 0; i < numberOfChangeEntries; i++) 500 { 501 pdrRecordHandles.push_back(changeEntryData[i]); 502 } 503 return PLDM_SUCCESS; 504 } 505 506 Response Handler::setNumericEffecterValue(const pldm_msg* request, 507 size_t payloadLength) 508 { 509 Response response(sizeof(pldm_msg_hdr) + 510 PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES); 511 uint16_t effecterId{}; 512 uint8_t effecterDataSize{}; 513 uint8_t effecterValue[4] = {}; 514 515 if ((payloadLength > sizeof(effecterId) + sizeof(effecterDataSize) + 516 sizeof(union_effecter_data_size)) || 517 (payloadLength < sizeof(effecterId) + sizeof(effecterDataSize) + 1)) 518 { 519 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 520 } 521 522 int rc = decode_set_numeric_effecter_value_req( 523 request, payloadLength, &effecterId, &effecterDataSize, 524 reinterpret_cast<uint8_t*>(&effecterValue)); 525 526 if (rc == PLDM_SUCCESS) 527 { 528 const pldm::utils::DBusHandler dBusIntf; 529 rc = platform_numeric_effecter::setNumericEffecterValueHandler< 530 pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId, 531 effecterDataSize, effecterValue, 532 sizeof(effecterValue)); 533 } 534 535 return ccOnlyResponse(request, rc); 536 } 537 538 } // namespace platform 539 } // namespace responder 540 } // namespace pldm 541