libpldm: add APIs for FRU record set PDR ops

Add APIs for:
- adding FRU record set PDRs to a PDR repository
- finding FRU record set PDRs in a PDR repository based on the FRU
  record set identifier.

Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Change-Id: I2b233af1325849cfc5d7de6a9a69af6771b222b2
diff --git a/libpldm/pdr.c b/libpldm/pdr.c
index 692a035..5e792a5 100644
--- a/libpldm/pdr.c
+++ b/libpldm/pdr.c
@@ -236,3 +236,68 @@
 
 	return record->record_handle;
 }
+
+uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
+				     uint16_t fru_rsi, uint16_t entity_type,
+				     uint16_t entity_instance_num,
+				     uint16_t container_id)
+{
+	uint32_t size = sizeof(struct pldm_pdr_hdr) +
+			sizeof(struct pldm_pdr_fru_record_set);
+	uint8_t data[size];
+
+	struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
+	hdr->version = 1;
+	hdr->record_handle = 0;
+	hdr->type = PLDM_PDR_FRU_RECORD_SET;
+	hdr->record_change_num = 0;
+	hdr->length = sizeof(struct pldm_pdr_fru_record_set);
+	struct pldm_pdr_fru_record_set *fru =
+	    (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
+					       sizeof(struct pldm_pdr_hdr));
+	fru->terminus_handle = terminus_handle;
+	fru->fru_rsi = fru_rsi;
+	fru->entity_type = entity_type;
+	fru->entity_instance_num = entity_instance_num;
+	fru->container_id = container_id;
+
+	return pldm_pdr_add(repo, data, size, 0);
+}
+
+const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
+    const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
+    uint16_t *entity_type, uint16_t *entity_instance_num,
+    uint16_t *container_id)
+{
+	assert(terminus_handle != NULL);
+	assert(entity_type != NULL);
+	assert(entity_instance_num != NULL);
+	assert(container_id != NULL);
+
+	uint8_t *data = NULL;
+	uint32_t size = 0;
+	const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
+	    repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
+	while (curr_record != NULL) {
+		struct pldm_pdr_fru_record_set *fru =
+		    (struct pldm_pdr_fru_record_set
+			 *)(data + sizeof(struct pldm_pdr_hdr));
+		if (fru->fru_rsi == fru_rsi) {
+			*terminus_handle = fru->terminus_handle;
+			*entity_type = fru->entity_type;
+			*entity_instance_num = fru->entity_instance_num;
+			*container_id = fru->container_id;
+			return curr_record;
+		}
+		data = NULL;
+		curr_record = pldm_pdr_find_record_by_type(
+		    repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data, &size);
+	}
+
+	*terminus_handle = 0;
+	*entity_type = 0;
+	*entity_instance_num = 0;
+	*container_id = 0;
+
+	return NULL;
+}
diff --git a/libpldm/pdr.h b/libpldm/pdr.h
index eb4a3bb..7fe0f23 100644
--- a/libpldm/pdr.h
+++ b/libpldm/pdr.h
@@ -133,6 +133,47 @@
 			     const pldm_pdr_record *curr_record, uint8_t **data,
 			     uint32_t *size);
 
+/* ======================= */
+/* FRU Record Set PDR APIs */
+/* ======================= */
+
+/** @brief Add a FRU record set PDR record to a PDR repository
+ *
+ *  @param[in/out] repo - opaque pointer acting as a PDR repo handle
+ *  @param[in] terminus_handle - PLDM terminus handle of terminus owning the PDR
+ *  record
+ *  @param[in] fru_rsi - FRU record set identifier
+ *  @param[in] entity_type - entity type of FRU
+ *  @param[in] entity_instance_num - entity instance number of FRU
+ *  @param[in] container_id - container id of FRU
+ *
+ *  @return uint32_t - record handle assigned to PDR record
+ */
+uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
+				     uint16_t fru_rsi, uint16_t entity_type,
+				     uint16_t entity_instance_num,
+				     uint16_t container_id);
+
+/** @brief Find a FRU record set PDR by FRU record set identifier
+ *
+ *  @param[in] repo - opaque pointer acting as a PDR repo handle
+ *  @param[in] fru_rsi - FRU record set identifier
+ *  @param[in] terminus_handle - *terminus_handle will be FRU terminus handle of
+ *  found PDR, or 0 if not found
+ *  @param[in] entity_type - *entity_type will be FRU entity type of found PDR,
+ *  or 0 if not found
+ *  @param[in] entity_instance_num - *entity_instance_num will be FRU entity
+ *  instance number of found PDR, or 0 if not found
+ *  @param[in] container_id - *cintainer_id will be FRU container id of found
+ *  PDR, or 0 if not found
+ *
+ *  @return uint32_t - record handle assigned to PDR record
+ */
+const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
+    const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
+    uint16_t *entity_type, uint16_t *entity_instance_num,
+    uint16_t *container_id);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libpldm/platform.h b/libpldm/platform.h
index 5341f6f..0cce1b4 100644
--- a/libpldm/platform.h
+++ b/libpldm/platform.h
@@ -45,6 +45,7 @@
  */
 enum pldm_pdr_types {
 	PLDM_STATE_EFFECTER_PDR = 11,
+	PLDM_PDR_FRU_RECORD_SET = 20,
 };
 
 /** @brief PLDM effecter initialization schemes
@@ -77,6 +78,18 @@
 	uint16_t length;
 } __attribute__((packed));
 
+/** @struct pldm_pdr_fru_record_set
+ *
+ *  Structure representing PLDM FRU record set PDR
+ */
+struct pldm_pdr_fru_record_set {
+	uint16_t terminus_handle;
+	uint16_t fru_rsi;
+	uint16_t entity_type;
+	uint16_t entity_instance_num;
+	uint16_t container_id;
+} __attribute__((packed));
+
 /** @struct pldm_state_effecter_pdr
  *
  *  Structure representing PLDM state effecter PDR