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