pdr: Add pldm_pdr_find_last_in_range()

Adds a new libpldm API to find the last PDR record from the PDR repo
based on the range of record handle values given as input. This API is
used when a record needs to be added in a particular range of record
handles to the repo that contains all PDRs (inclusive of BMC and remote
endpoints).

Change-Id: Ica5187053361b27810577a4985fab4b994d35961
Signed-off-by: Pavithra Barithaya <pavithra.b@ibm.com>
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d76c6a8..9d7a152 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,7 @@
 2. README: Add a section on working with libpldm
 3. pdr: Introduce remote_container_id and associated APIs
 4. pdr: Add APIs for creating and locating remote PDRs
+5. pdr: Add pldm_pdr_find_last_in_range()
 
 ### Changed
 
diff --git a/include/libpldm/pdr.h b/include/libpldm/pdr.h
index 7542624..dc4928c 100644
--- a/include/libpldm/pdr.h
+++ b/include/libpldm/pdr.h
@@ -167,6 +167,19 @@
 void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
 			    uint8_t tid, uint8_t tl_eid, bool valid);
 
+/** @brief Find the last record within the particular range
+ * of record handles
+ *
+ *  @param[in] repo - pointer acting as a PDR repo handle
+ *  @param[in] first - first record handle value of the records in the range
+ *  @param[in] last - last record handle value of the records in the range
+ *
+ *  @return pointer to the PDR record,will be NULL if record was not
+ *  found
+ */
+pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
+					     uint32_t first, uint32_t last);
+
 /* ======================= */
 /* FRU Record Set PDR APIs */
 /* ======================= */
diff --git a/src/pdr.c b/src/pdr.c
index 752fd57..8a63e95 100644
--- a/src/pdr.c
+++ b/src/pdr.c
@@ -966,6 +966,28 @@
 	}
 }
 
+LIBPLDM_ABI_TESTING
+pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
+					     uint32_t first, uint32_t last)
+{
+	pldm_pdr_record *record = NULL;
+	pldm_pdr_record *curr;
+
+	if (!repo) {
+		return NULL;
+	}
+	for (curr = repo->first; curr; curr = curr->next) {
+		if (first > curr->record_handle || last < curr->record_handle) {
+			continue;
+		}
+		if (!record || curr->record_handle > record->record_handle) {
+			record = curr;
+		}
+	}
+
+	return record;
+}
+
 static void entity_association_tree_find_if_remote(pldm_entity_node *node,
 						   pldm_entity *entity,
 						   pldm_entity_node **out,
diff --git a/tests/libpldm_pdr_test.cpp b/tests/libpldm_pdr_test.cpp
index 72860d7..f29fb97 100644
--- a/tests/libpldm_pdr_test.cpp
+++ b/tests/libpldm_pdr_test.cpp
@@ -547,6 +547,34 @@
     pldm_pdr_destroy(repo);
 }
 
+#ifdef LIBPLDM_API_TESTING
+TEST(PDRUpdate, testFindLastInRange)
+{
+    auto repo = pldm_pdr_init();
+
+    std::array<uint8_t, 10> data{};
+    auto handle1 = pldm_pdr_add(repo, data.data(), data.size(), 0, false, 1);
+    auto handle2 = pldm_pdr_add(repo, data.data(), data.size(), 23, false, 1);
+    auto handle3 = pldm_pdr_add(repo, data.data(), data.size(), 77, false, 1);
+    auto handle4 =
+        pldm_pdr_add(repo, data.data(), data.size(), 16777325, true, 1);
+    auto handle5 =
+        pldm_pdr_add(repo, data.data(), data.size(), 16777344, true, 1);
+
+    auto rec1 = pldm_pdr_find_last_in_range(repo, 0, 100);
+    auto rec2 = pldm_pdr_find_last_in_range(repo, 16777300, 33554431);
+    EXPECT_NE(rec1, nullptr);
+    EXPECT_NE(rec2, nullptr);
+    EXPECT_NE(handle1, pldm_pdr_get_record_handle(repo, rec1));
+    EXPECT_NE(handle2, pldm_pdr_get_record_handle(repo, rec1));
+    EXPECT_EQ(handle3, pldm_pdr_get_record_handle(repo, rec1));
+    EXPECT_NE(handle4, pldm_pdr_get_record_handle(repo, rec2));
+    EXPECT_EQ(handle5, pldm_pdr_get_record_handle(repo, rec2));
+
+    pldm_pdr_destroy(repo);
+}
+#endif
+
 TEST(EntityAssociationPDR, testInit)
 {
     auto tree = pldm_entity_association_tree_init();