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