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