| #include "helper/discovery/rde_discovery.hpp" |
| |
| #include "libpldm/base.h" |
| #include "libpldm/pldm.h" |
| #include "libpldm/pldm_rde.h" |
| #include "libpldm/requester/pldm_rde_requester.h" |
| #include "libpldm/utils.h" |
| |
| #include "helper/common.hpp" |
| |
| #include <algorithm> |
| #include <cstdint> |
| #include <iostream> |
| #include <map> |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <tuple> |
| #include <unordered_map> |
| #include <vector> |
| |
| std::unordered_map<std::string, int> managerCtxCounter; |
| std::unordered_map<std::string, |
| std::unique_ptr<struct pldm_rde_requester_manager>> |
| managers; |
| std::vector<struct pldm_rde_requester_context> rdeContexts; |
| // This map will store dictionaries for each of the RDE Devices separately |
| std::unordered_map<std::string, |
| std::unordered_map<uint32_t, std::vector<uint8_t>>> |
| dictionaryDeviceMap; |
| std::unordered_map<std::string, |
| std::unordered_map<uint32_t, std::tuple<uint8_t, uint8_t>>> |
| dictionaryMetaDeviceMap; |
| |
| int rdeContextCounter = 0; |
| std::unordered_map<uint8_t, int> rdeCommandRequestSize = { |
| {PLDM_NEGOTIATE_REDFISH_PARAMETERS, 3}, |
| {PLDM_NEGOTIATE_MEDIUM_PARAMETERS, 4}, |
| {PLDM_GET_SCHEMA_DICTIONARY, 5}, |
| {PLDM_RDE_MULTIPART_RECEIVE, 7}}; |
| |
| void cleanupRdeDiscAtExit() |
| { |
| managerCtxCounter.clear(); |
| managers.clear(); |
| rdeContexts.clear(); |
| dictionaryDeviceMap.clear(); |
| dictionaryMetaDeviceMap.clear(); |
| rdeCommandRequestSize.clear(); |
| } |
| |
| int printRDENegotiateContext(struct pldm_rde_requester_manager* mgr) |
| { |
| std::cerr << "====================================================\n"; |
| std::cerr << "***RDE Negotiate/Medium Parameters Begins***\n"; |
| std::cerr << "====================================================\n"; |
| |
| std::cerr << "MC Concurrency: " << std::to_string(mgr->mc_concurrency) |
| << "\n"; |
| std::cerr << "MC Transfer Size: " << std::to_string(mgr->mc_transfer_size) |
| << "\n"; |
| |
| std::cerr << "miniBMC Concurrency: " |
| << std::to_string(mgr->device.device_concurrency) << "\n"; |
| std::cerr << "miniBMC Device Capabilities Flag: " |
| << std::to_string(mgr->device.device_capabilities_flag.byte) |
| << "\n"; |
| std::cerr << "miniBMC Device Feature Support: " |
| << std::to_string(mgr->device.device_feature_support.value) |
| << "\n"; |
| std::cerr << "miniBMC Device Configuration Signature: " |
| << std::to_string(mgr->device.device_configuration_signature) |
| << "\n"; |
| std::cerr << "miniBMC Device Provider Name (Eid): " |
| << std::to_string( |
| mgr->device.device_provider_name.string_length_bytes) |
| << "\n"; |
| |
| std::cerr << "Device max buffer size: " |
| << std::to_string(mgr->device.device_maximum_transfer_chunk_size) |
| << std::endl; |
| |
| std::cerr << "Negotiated Transfer Size (Medium Parameters): " |
| << std::to_string(mgr->negotiated_transfer_size) << "\n"; |
| |
| std::cerr << "====================================================\n"; |
| std::cerr << "***RDE Negotiate/Medium Parameters Ends***\n"; |
| std::cerr << "====================================================\n"; |
| return 0; |
| } |
| |
| // Removes manager for rde device |
| void removeManagerForRdeDevice(const std::string& rdeDevice) |
| { |
| auto it = managers.find(rdeDevice); |
| if (it != managers.end()) |
| { |
| managers.erase(rdeDevice); |
| } |
| } |
| |
| // Callback function to allocate memory to contexts and keep them in an array |
| struct pldm_rde_requester_context* |
| allocateMemoryToContexts(uint8_t numberOfContexts) |
| { |
| int end = rdeContextCounter + numberOfContexts; |
| for (; rdeContextCounter < end; rdeContextCounter++) |
| { |
| struct pldm_rde_requester_context currentCtx = {}; |
| if (pldm_rde_create_context(¤tCtx)) |
| { |
| return nullptr; |
| } |
| rdeContexts.emplace_back(currentCtx); |
| } |
| return &rdeContexts[rdeContextCounter - 1]; |
| } |
| |
| void freeMemory(void* context) |
| { |
| free(context); |
| } |
| |
| void cleanupDictionaries(const std::string& rdeDeviceId) |
| { |
| std::cerr << "Dict size before cleanup" << dictionaryDeviceMap.size() |
| << std::endl; |
| dictionaryDeviceMap.erase(rdeDeviceId); |
| dictionaryMetaDeviceMap.erase(rdeDeviceId); |
| |
| std::cerr << "Dict size after cleanup" << dictionaryDeviceMap.size() |
| << std::endl; |
| } |
| |
| int initManager(const std::string& rdeDeviceId, int netId) |
| { |
| // TODO(@harshtya): Cleanup memory when device is removed. |
| uint8_t mcConcurrency = 3; |
| uint32_t mcTransferSize = PLDM_MAX_REQUEST_BYTES; |
| std::unique_ptr<bitfield16_t> mcFeatures = std::make_unique<bitfield16_t>(); |
| mcFeatures->value = 102; // Fixed for now |
| std::cout << "Initializing RDE Manager...\n"; |
| |
| std::unique_ptr<struct pldm_rde_requester_manager> manager = |
| std::make_unique<struct pldm_rde_requester_manager>(); |
| |
| managerCtxCounter.insert({rdeDeviceId, rdeContextCounter}); |
| int rc = pldm_rde_init_context( |
| rdeDeviceId.c_str(), netId, manager.get(), mcConcurrency, |
| mcTransferSize, mcFeatures.get(), allocateMemoryToContexts, freeMemory); |
| |
| if (rc) |
| { |
| std::cerr |
| << "RDE Discovery failed due to context initialization error: " |
| << rc << "\n"; |
| return rc; |
| } |
| |
| // remove if exists and then emplace |
| removeManagerForRdeDevice(rdeDeviceId); |
| managers.emplace(rdeDeviceId, std::move(manager)); |
| return PLDM_RDE_REQUESTER_SUCCESS; |
| } |
| |
| /** |
| * @param[in] manager - Rde manager for the device |
| * @param[in] resourceIds - List of dictionary schema resource IDs |
| * @return 0 on success, non zero error code on failure. |
| */ |
| static int setResourcesIdsInManager(struct pldm_rde_requester_manager* manager, |
| std::vector<uint32_t>& resourceIds) |
| { |
| return pldm_rde_set_resources_in_context(manager, resourceIds.size(), |
| resourceIds.data()); |
| } |
| |
| int getRdeContextForRdeDevice(const std::string& rdeDevice) |
| { |
| auto it = managerCtxCounter.find(rdeDevice); |
| if (it != managerCtxCounter.end()) |
| { |
| return it->second; |
| } |
| return -1; |
| } |
| |
| std::optional<struct pldm_rde_requester_manager*> |
| getManagerForRdeDevice(const std::string& rdeDevice) |
| { |
| auto it = managers.find(rdeDevice); |
| if (it != managers.end()) |
| { |
| return it->second.get(); |
| } |
| return std::nullopt; |
| } |
| |
| int processNegotiateRedfishParametersRequest( |
| int fd, uint8_t eid, int instanceId, |
| struct pldm_rde_requester_manager* manager, |
| struct pldm_rde_requester_context* ctx, |
| const std::vector<uint8_t>& requestMsg) |
| { |
| ctx->context_status = CONTEXT_BUSY; |
| ctx->requester_status = PLDM_RDE_REQUESTER_WAITING_FOR_RESPONSE; |
| int rc = pldm_send_at_network(eid, manager->net_id, fd, requestMsg.data(), |
| requestMsg.size()); |
| if (rc) |
| { |
| ctx->requester_status = PLDM_RDE_REQUESTER_REQUEST_FAILED; |
| ctx->context_status = CONTEXT_FREE; |
| return PLDM_RDE_REQUESTER_SEND_FAIL; |
| } |
| std::vector<uint8_t> response(sizeof(pldm_msg_hdr) + PLDM_MAX_REQUEST_BYTES, |
| 0); |
| uint8_t* responseMsg = response.data(); |
| size_t responseMsgSize = response.size(); |
| auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg); |
| rc = pldm_recv_at_network(eid, fd, instanceId, &responseMsg, |
| &responseMsgSize, manager->net_id); |
| if (rc) |
| { |
| ctx->requester_status = PLDM_RDE_REQUESTER_REQUEST_FAILED; |
| return PLDM_RDE_REQUESTER_RECV_FAIL; |
| } |
| |
| std::cerr << "Pushing Response for Negotiate Redfish Parameters...\n"; |
| |
| rc = pldm_rde_discovery_push_response(manager, ctx, responsePtr, |
| responseMsgSize); |
| |
| if (rc) |
| { |
| ctx->requester_status = PLDM_RDE_REQUESTER_REQUEST_FAILED; |
| ctx->context_status = CONTEXT_FREE; |
| std::cerr << "Saving RDE Disc. Response Failed..." << std::endl; |
| return PLDM_RDE_REQUESTER_NOT_RESP_MSG; |
| } |
| return PLDM_BASE_REQUESTER_SUCCESS; |
| } |
| |
| int processNegotiateMediumParametersRequest( |
| int fd, uint8_t eid, int instanceId, |
| struct pldm_rde_requester_manager* manager, |
| struct pldm_rde_requester_context* ctx, |
| const std::vector<uint8_t>& requestMsg) |
| { |
| ctx->context_status = CONTEXT_BUSY; |
| ctx->requester_status = PLDM_RDE_REQUESTER_WAITING_FOR_RESPONSE; |
| int rc = pldm_send_at_network(eid, manager->net_id, fd, requestMsg.data(), |
| requestMsg.size()); |
| if (rc) |
| { |
| ctx->requester_status = PLDM_RDE_REQUESTER_REQUEST_FAILED; |
| ctx->context_status = CONTEXT_FREE; |
| return PLDM_RDE_REQUESTER_SEND_FAIL; |
| } |
| |
| std::vector<uint8_t> response( |
| sizeof(pldm_msg_hdr) + RDE_NEGOTIATE_REDFISH_MEDIUM_PARAMS_RESP_SIZE, |
| 0); |
| uint8_t* responseMsg = response.data(); |
| size_t responseMsgSize = sizeof(pldm_msg_hdr) + |
| RDE_NEGOTIATE_REDFISH_MEDIUM_PARAMS_RESP_SIZE; |
| auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg); |
| |
| rc = pldm_recv_at_network(eid, fd, instanceId, &responseMsg, |
| &responseMsgSize, manager->net_id); |
| if (rc) |
| { |
| ctx->requester_status = PLDM_RDE_REQUESTER_REQUEST_FAILED; |
| ctx->context_status = CONTEXT_FREE; |
| return PLDM_RDE_REQUESTER_RECV_FAIL; |
| } |
| |
| std::cerr << "Pushing Response for Negotiate Medium Parameters...\n"; |
| |
| rc = pldm_rde_discovery_push_response(manager, ctx, responsePtr, |
| responseMsgSize); |
| if (rc) |
| { |
| ctx->requester_status = PLDM_RDE_REQUESTER_REQUEST_FAILED; |
| ctx->context_status = CONTEXT_FREE; |
| std::cerr << "Saving RDE Disc. (Med) Response Failed..." << std::endl; |
| return PLDM_RDE_REQUESTER_NOT_RESP_MSG; |
| } |
| return PLDM_RDE_REQUESTER_SUCCESS; |
| } |
| |
| std::optional<std::unordered_map<uint32_t, std::vector<uint8_t>>*> |
| getDictionaryMap(const std::string& rdeDevice) |
| { |
| if (DEBUG) |
| { |
| std::cerr << "Searching dict for: " << rdeDevice |
| << "with length: " << std::to_string(rdeDevice.length()) |
| << "\n"; |
| } |
| auto it = dictionaryDeviceMap.find(rdeDevice); |
| if (it != dictionaryDeviceMap.end()) |
| { |
| return &(it->second); |
| } |
| return std::nullopt; |
| } |
| |
| int verifyChecksumForMultipartRecv(const std::vector<uint8_t>& payload) |
| { |
| uint32_t payloadLength = payload.size(); |
| auto calculatedChecksum = crc32(&(payload.front()), payloadLength - 4); |
| uint8_t byte0 = payload[payloadLength - 4]; |
| uint8_t byte1 = payload[payloadLength - 3]; |
| uint8_t byte2 = payload[payloadLength - 2]; |
| uint8_t byte3 = payload[payloadLength - 1]; |
| |
| uint32_t checksumReceived = byte0 | byte1 << 8 | byte2 << 16 | byte3 << 24; |
| if (calculatedChecksum == checksumReceived) |
| { |
| if (DEBUG) |
| { |
| std::cerr << "For RDE Op: Checksum Verified, Calculated Checksum: " |
| << std::to_string(calculatedChecksum) |
| << " , Received Checksum: " |
| << std::to_string(checksumReceived) << std::endl; |
| } |
| return PLDM_RDE_REQUESTER_SUCCESS; |
| } |
| std::cerr |
| << "Checksum mismatch for request id/resource id in multipart receive" |
| << std::endl; |
| return PLDM_RDE_REQUESTER_RECV_FAIL; |
| } |
| |
| void getDictMultipartResponseHandler(struct pldm_rde_requester_manager* manager, |
| struct pldm_rde_requester_context* ctx, |
| uint8_t** payload, uint32_t payloadLength, |
| bool hasChecksum) |
| { |
| uint8_t resourceIdIndex = ctx->current_pdr_resource->resource_id_index; |
| uint32_t resourceId = manager->resource_ids[resourceIdIndex]; |
| |
| if (DEBUG) |
| { |
| std::cerr << "Resource id pushing in dictionary...\t" |
| << std::to_string(resourceIdIndex) |
| << " and Resource id: " << std::to_string(resourceId) << "\n"; |
| } |
| std::string device_id = std::string(manager->device_name); |
| std::unordered_map<uint32_t, std::vector<uint8_t>>* dictionaryRidMap; |
| |
| std::optional<std::unordered_map<uint32_t, std::vector<uint8_t>>*> |
| dictionaryRidMapOpt = getDictionaryMap(device_id); |
| |
| if (dictionaryRidMapOpt.has_value()) |
| { |
| dictionaryRidMap = dictionaryRidMapOpt.value(); |
| std::cout << dictionaryRidMap->size(); |
| } |
| else |
| { |
| std::cerr << "Unable to fetch dictionary from map while storing\n"; |
| return; |
| } |
| |
| auto it = dictionaryRidMap->find(resourceId); |
| std::vector<uint8_t>* dictionary; |
| if (it != dictionaryRidMap->end()) |
| { |
| dictionary = &(it->second); |
| dictionary->insert(it->second.end(), *payload, |
| (*payload) + payloadLength); |
| } |
| else |
| { |
| (*dictionaryRidMap)[resourceId] = |
| std::vector<uint8_t>(*payload, *payload + payloadLength); |
| dictionary = &(*dictionaryRidMap)[resourceId]; |
| } |
| if (DEBUG) |
| { |
| std::cerr << "Payload Length inside creating map for resource id << " |
| << std::to_string( |
| ctx->current_pdr_resource->resource_id_index) |
| << ": " << payloadLength << "\n"; |
| } |
| |
| if (hasChecksum) |
| { |
| int rc = verifyChecksumForMultipartRecv(*dictionary); |
| if (rc) |
| { |
| std::cerr << "Checksum verification for dictionary failed\n"; |
| } |
| else |
| { |
| if (DEBUG) |
| { |
| std::cerr << "Checksum verified delteing last 4 payload\n"; |
| } |
| dictionary->erase(dictionary->begin() + (dictionary->size() - 4), |
| dictionary->end()); |
| } |
| } |
| } |
| |
| void responseHandlerCallback(struct pldm_rde_requester_manager* manager, |
| struct pldm_rde_requester_context* ctx, |
| uint8_t** payload, uint32_t payloadLength, |
| bool hasChecksum) |
| { |
| switch (ctx->next_command) |
| { |
| case PLDM_RDE_MULTIPART_RECEIVE: |
| getDictMultipartResponseHandler(manager, ctx, payload, |
| payloadLength, hasChecksum); |
| break; |
| default: |
| break; // No Op for other commands- Can add functionalities later |
| } |
| } |
| |
| int processGetNextDictionarySchema(int fd, uint8_t eid, int instanceId, |
| struct pldm_rde_requester_manager* manager, |
| struct pldm_rde_requester_context* ctx, |
| const std::vector<uint8_t>& requestMsg) |
| { |
| ctx->context_status = CONTEXT_BUSY; |
| ctx->requester_status = PLDM_RDE_REQUESTER_WAITING_FOR_RESPONSE; |
| int rc = pldm_send_at_network(eid, manager->net_id, fd, requestMsg.data(), |
| requestMsg.size()); |
| if (rc) |
| { |
| ctx->requester_status = PLDM_RDE_REQUESTER_REQUEST_FAILED; |
| ctx->context_status = CONTEXT_FREE; |
| return PLDM_RDE_REQUESTER_SEND_FAIL; |
| } |
| std::vector<uint8_t> response( |
| sizeof(pldm_msg_hdr) + RDE_GET_DICT_SCHEMA_RESP_SIZE, 0); |
| uint8_t* responseMsg = response.data(); |
| size_t responseMsgSize = sizeof(pldm_msg_hdr) + |
| RDE_GET_DICT_SCHEMA_RESP_SIZE; |
| auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg); |
| |
| rc = pldm_recv_at_network(eid, fd, instanceId, &responseMsg, |
| &responseMsgSize, manager->net_id); |
| if (rc) |
| { |
| ctx->requester_status = PLDM_RDE_REQUESTER_REQUEST_FAILED; |
| ctx->context_status = CONTEXT_FREE; |
| return PLDM_RDE_REQUESTER_RECV_FAIL; |
| } |
| |
| rc = pldm_rde_push_get_dictionary_response( |
| manager, ctx, responsePtr, responseMsgSize, responseHandlerCallback); |
| |
| if (rc) |
| { |
| ctx->requester_status = PLDM_RDE_REQUESTER_REQUEST_FAILED; |
| ctx->context_status = CONTEXT_FREE; |
| std::cerr << "Saving Dictionary Response Failed..." << std::endl; |
| return PLDM_RDE_REQUESTER_NOT_RESP_MSG; |
| } |
| |
| return PLDM_RDE_REQUESTER_SUCCESS; |
| } |
| |
| int processRdeMultipartReceive(int fd, uint8_t eid, int instanceId, |
| struct pldm_rde_requester_manager* manager, |
| struct pldm_rde_requester_context* ctx, |
| const std::vector<uint8_t>& requestMsg) |
| { |
| ctx->context_status = CONTEXT_BUSY; |
| ctx->requester_status = PLDM_RDE_REQUESTER_WAITING_FOR_RESPONSE; |
| int rc = pldm_send_at_network(eid, manager->net_id, fd, requestMsg.data(), |
| requestMsg.size()); |
| if (rc) |
| { |
| ctx->requester_status = PLDM_RDE_REQUESTER_REQUEST_FAILED; |
| ctx->context_status = CONTEXT_FREE; |
| return PLDM_RDE_REQUESTER_SEND_FAIL; |
| } |
| std::vector<uint8_t> response( |
| sizeof(pldm_msg_hdr) + manager->negotiated_transfer_size, 0); |
| uint8_t* responseMsg = response.data(); |
| size_t responseMsgSize = sizeof(pldm_msg_hdr) + |
| manager->negotiated_transfer_size; |
| auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg); |
| |
| rc = pldm_recv_at_network(eid, fd, instanceId, &responseMsg, |
| &responseMsgSize, manager->net_id); |
| if (rc) |
| { |
| ctx->requester_status = PLDM_RDE_REQUESTER_REQUEST_FAILED; |
| ctx->context_status = CONTEXT_FREE; |
| return PLDM_RDE_REQUESTER_RECV_FAIL; |
| } |
| |
| if (DEBUG) |
| { |
| auto resourceId = |
| manager->resource_ids[ctx->current_pdr_resource->resource_id_index]; |
| auto transferHandleCurrent = ctx->current_pdr_resource->transfer_handle; |
| std::cerr |
| << "Pushing response for Get Multipart receive for resource id: " |
| << std::to_string(resourceId) |
| << " and transfer handle: " << std::to_string(transferHandleCurrent) |
| << "...\n"; |
| } |
| rc = pldm_rde_push_get_dictionary_response( |
| manager, ctx, responsePtr, responseMsgSize, responseHandlerCallback); |
| if (rc) |
| { |
| ctx->requester_status = PLDM_RDE_REQUESTER_REQUEST_FAILED; |
| ctx->context_status = CONTEXT_FREE; |
| std::cerr << "Saving Dictionary Response Failed..." << std::endl; |
| return PLDM_RDE_REQUESTER_NOT_RESP_MSG; |
| } |
| |
| return PLDM_RDE_REQUESTER_SUCCESS; |
| } |
| |
| int processNextRdeRequest(int fd, uint8_t eid, int instanceId, |
| struct pldm_rde_requester_manager* manager, |
| struct pldm_rde_requester_context* ctx, |
| const std::vector<uint8_t>& requestMsg) |
| { |
| switch (ctx->next_command) |
| { |
| case PLDM_NEGOTIATE_REDFISH_PARAMETERS: |
| return processNegotiateRedfishParametersRequest( |
| fd, eid, instanceId, manager, ctx, requestMsg); |
| |
| case PLDM_NEGOTIATE_MEDIUM_PARAMETERS: |
| return processNegotiateMediumParametersRequest( |
| fd, eid, instanceId, manager, ctx, requestMsg); |
| |
| case PLDM_GET_SCHEMA_DICTIONARY: |
| return processGetNextDictionarySchema(fd, eid, instanceId, manager, |
| ctx, requestMsg); |
| |
| case PLDM_RDE_MULTIPART_RECEIVE: |
| return processRdeMultipartReceive(fd, eid, instanceId, manager, ctx, |
| requestMsg); |
| |
| default: |
| return PLDM_RDE_REQUESTER_NOT_PLDM_RDE_MSG; |
| } |
| } |
| |
| int performRdeDiscovery(const std::string& rdeDeviceId, int fd, int netId, |
| uint8_t destEid, uint8_t instanceId, |
| uint32_t& negotiatedTransferSize) |
| { |
| int rc = initManager(rdeDeviceId, netId); |
| if (rc) |
| { |
| std::cerr << "initManager failed with error: " << rc << "\n"; |
| return rc; |
| } |
| |
| int rdeContextIndex = getRdeContextForRdeDevice(rdeDeviceId); |
| if (rdeContextIndex == -1) |
| { |
| std::cerr |
| << "Unable to provide base context- Error in RDE discovery\n "; |
| return -1; |
| } |
| |
| struct pldm_rde_requester_context baseContext = |
| rdeContexts[rdeContextIndex]; |
| |
| rc = pldm_rde_start_discovery(&baseContext); |
| if (rc) |
| { |
| std::cerr << "RDE Discovery failed due to context busy with ec: " << rc |
| << "\n"; |
| return -1; |
| } |
| |
| std::optional<struct pldm_rde_requester_manager*> managerOpt = |
| getManagerForRdeDevice(rdeDeviceId); |
| |
| if (!managerOpt.has_value()) |
| { |
| std::cerr << "Failure to get RDE Manager for rde device with ec: " << rc |
| << "\n"; |
| return -1; |
| } |
| struct pldm_rde_requester_manager* manager = managerOpt.value(); |
| |
| int retryCounter = 0; |
| while (true) |
| { |
| int requestBytes; |
| if (baseContext.requester_status == |
| PLDM_RDE_REQUESTER_NO_PENDING_ACTION) |
| { |
| break; |
| } |
| if (rdeCommandRequestSize.find(baseContext.next_command) != |
| rdeCommandRequestSize.end()) |
| { |
| requestBytes = rdeCommandRequestSize[baseContext.next_command]; |
| } |
| else |
| { |
| requestBytes = PLDM_MAX_REQUEST_BYTES; |
| } |
| |
| std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + requestBytes); |
| auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); |
| std::cout << "Getting next RDE Discovery request...\n"; |
| |
| rc = pldm_rde_get_next_discovery_command(instanceId, manager, |
| &baseContext, request); |
| if (rc) |
| { |
| std::cerr << "Not a valid request to process\n"; |
| return rc; |
| } |
| |
| rc = processNextRdeRequest(fd, destEid, 1, manager, &baseContext, |
| requestMsg); |
| |
| if (rc) |
| { |
| std::cerr << "Unable to process next rde request: " |
| << std::to_string(rc) << "\n"; |
| return rc; |
| } |
| retryCounter++; |
| if (retryCounter > 5) |
| { |
| std::cerr << "All process counters exhausted for RDE discovery" |
| << std::endl; |
| rc = -1; |
| } |
| } |
| |
| negotiatedTransferSize = manager->negotiated_transfer_size; |
| |
| if (DEBUG) |
| { |
| printRDENegotiateContext(manager); |
| } |
| return rc; |
| } |
| |
| int performDictionaryDiscoveryForDevice( |
| const std::string& rdeDeviceId, int fd, uint8_t destEid, uint8_t instanceId, |
| std::unordered_map<std::string, uint32_t>& resourceIdMap) |
| { |
| std::unordered_map<uint32_t, std::vector<uint8_t>> dictionaryRidMap; |
| std::unordered_map<uint32_t, std::tuple<uint8_t, uint8_t>> |
| dictionaryMetaRidMap; |
| std::vector<uint32_t> schemaResourceIds; |
| |
| for (const auto& [key, value] : resourceIdMap) |
| { |
| // We need to extract just the schema resource IDs. There will be |
| // multiple resources which share the same schema, but we only need |
| // the resource ID of the first resource of that schema |
| // For e.g. We only need resource ID of /redfish/v1/Chassis/Tray i.e. |
| // 0x00020000 instead of resource ID of /redfish/v1/Chassis/SATA_0 i.e. |
| // 0x00020001. Here the MSB 0x0002 represents the resource type while |
| // the LSB 0x0001 represent the resource index. So we exclude the |
| // resource index |
| uint32_t schemaResourceId = value & 0xFFFF0000; |
| auto it = std::find(schemaResourceIds.begin(), schemaResourceIds.end(), |
| schemaResourceId); |
| if (it == schemaResourceIds.end()) |
| { |
| schemaResourceIds.emplace_back(schemaResourceId); |
| } |
| } |
| // Add the annotation dictionary |
| schemaResourceIds.emplace_back(0xffffffff); |
| |
| dictionaryDeviceMap.insert({rdeDeviceId, dictionaryRidMap}); |
| |
| // For holding schema initial transfer flags - not being used right now |
| dictionaryMetaDeviceMap.insert({rdeDeviceId, dictionaryMetaRidMap}); |
| |
| int rdeContextIndex = getRdeContextForRdeDevice(rdeDeviceId); |
| if (rdeContextIndex == -1) |
| { |
| std::cerr << "Unable to provide base context- Error in RDE discovery\n"; |
| return -1; |
| } |
| |
| struct pldm_rde_requester_context baseContext = |
| rdeContexts[rdeContextIndex]; |
| int rc = pldm_rde_init_get_dictionary_schema(&baseContext); |
| if (rc) |
| { |
| std::cerr << "PLDM RDE Init dictionary failed with ec: " << rc << "\n"; |
| return rc; |
| } |
| if (DEBUG) |
| { |
| std::cerr << "Getting dictionary for context resource id : " |
| << std::to_string( |
| (baseContext.current_pdr_resource)->resource_id_index) |
| << "\n"; |
| } |
| |
| std::optional<struct pldm_rde_requester_manager*> managerOpt = |
| getManagerForRdeDevice(rdeDeviceId); |
| |
| if (!managerOpt.has_value()) |
| { |
| std::cerr << "Failure to get RDE Manager for rde device with ec: " << rc |
| << "\n"; |
| return -1; |
| } |
| struct pldm_rde_requester_manager* manager = managerOpt.value(); |
| |
| rc = setResourcesIdsInManager(manager, schemaResourceIds); |
| if (rc) |
| { |
| std::cerr |
| << "RDE Discovery failed due to failed to set resource IDs in context: " |
| << rc << "\n"; |
| return -1; |
| } |
| |
| std::cout << "Getting Dictionaries..." << std::endl; |
| int retryCounter = 0; |
| while (retryCounter < MAX_RETRIES_FOR_REQUEST) |
| { |
| int requestBytes; |
| if (baseContext.requester_status == |
| PLDM_RDE_REQUESTER_NO_PENDING_ACTION) |
| { |
| break; |
| } |
| if (rdeCommandRequestSize.find(baseContext.next_command) != |
| rdeCommandRequestSize.end()) |
| { |
| requestBytes = rdeCommandRequestSize[baseContext.next_command]; |
| } |
| else |
| { |
| requestBytes = PLDM_MAX_REQUEST_BYTES; |
| } |
| std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + requestBytes); |
| auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); |
| |
| if (baseContext.next_command == PLDM_GET_SCHEMA_DICTIONARY) |
| { |
| std::cerr << "Getting dictionary for " |
| << manager->resource_ids[baseContext.current_pdr_resource |
| ->resource_id_index] |
| << "..." << std::endl; |
| } |
| |
| rc = pldm_rde_get_next_dictionary_schema_command( |
| /*instanceId*/ instanceId, manager, &baseContext, request); |
| |
| if (rc) |
| { |
| std::cerr << "Not a valid request to process\n"; |
| return -1; |
| } |
| |
| rc = processNextRdeRequest(fd, destEid, instanceId, manager, |
| &baseContext, requestMsg); |
| |
| if (rc) |
| { |
| std::cerr << "Unable to process next rde request: " |
| << std::to_string(rc) << "\n"; |
| return -1; |
| } |
| retryCounter++; |
| } |
| |
| return 0; |
| } |
| |
| int getRdeFreeContextForRdeDevice( |
| const std::string& rdeDevice, |
| struct pldm_rde_requester_context* baseContext) |
| { |
| auto it = managerCtxCounter.find(rdeDevice); |
| if (it != managerCtxCounter.end()) |
| { |
| *baseContext = rdeContexts[it->second]; |
| if (baseContext->context_status != CONTEXT_FREE) |
| { |
| return RDE_CONTEXT_NOT_FREE; |
| } |
| return RDE_CONTEXT_FREE; |
| } |
| return RDE_NO_CONTEXT_FOUND; |
| } |
| |
| int getDictionaryForRidDev(const std::string& rdeDeviceId, uint32_t resourceId, |
| [[maybe_unused]] uint8_t** dictElem, |
| [[maybe_unused]] uint32_t* dictLength) |
| { |
| std::unordered_map<uint32_t, std::vector<uint8_t>>* dictionaryRidMap; |
| |
| std::optional<std::unordered_map<uint32_t, std::vector<uint8_t>>*> |
| dictionaryRidMapOpt = getDictionaryMap(rdeDeviceId); |
| |
| if (!dictionaryRidMapOpt.has_value()) |
| { |
| std::cerr << "Unable to fetch dictionary from map while storing\n"; |
| return PLDM_RDE_NO_PDR_RESOURCES_FOUND; |
| } |
| dictionaryRidMap = dictionaryRidMapOpt.value(); |
| auto it = dictionaryRidMap->find(resourceId); |
| if (it != dictionaryRidMap->end()) |
| { |
| *dictElem = &it->second.front(); |
| *dictLength = it->second.size(); |
| return PLDM_RDE_REQUESTER_SUCCESS; |
| } |
| else |
| { |
| dictElem = nullptr; |
| } |
| return PLDM_RDE_NO_PDR_RESOURCES_FOUND; |
| } |