fw_update: Add encode req & decode resp for query_downtream_identifiers

Add support for Query Downstream Identifiers to ask all downstream
devices' Descriptors managed by a endpoint.

The code is developed based on the definition of
'QueryDownstreamIdentifiers' in DSP0267_1.1.0 Section 10.4

Change-Id: I6282a894c73b78470c147e77d81e5a4ddd6a39a8
Signed-off-by: Delphine CC Chiu <Delphine_CC_Chiu@wiwynn.com>
diff --git a/src/firmware_update.c b/src/firmware_update.c
index ed1816d..4aafadc 100644
--- a/src/firmware_update.c
+++ b/src/firmware_update.c
@@ -86,6 +86,18 @@
 	}
 }
 
+static bool
+is_transfer_operation_flag_valid(enum transfer_op_flag transfer_op_flag)
+{
+	switch (transfer_op_flag) {
+	case PLDM_GET_NEXTPART:
+	case PLDM_GET_FIRSTPART:
+		return true;
+	default:
+		return false;
+	}
+}
+
 /** @brief Check whether ComponentResponse is valid
  *
  *  @return true if ComponentResponse is valid, false if not
@@ -928,6 +940,100 @@
 	return pldm_msgbuf_destroy_consumed(buf);
 }
 
+LIBPLDM_ABI_TESTING
+int encode_query_downstream_identifiers_req(
+	uint8_t instance_id, uint32_t data_transfer_handle,
+	enum transfer_op_flag transfer_operation_flag, struct pldm_msg *msg,
+	size_t payload_length)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (!is_transfer_operation_flag_valid(transfer_operation_flag)) {
+		return PLDM_INVALID_TRANSFER_OPERATION_FLAG;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.pldm_type = PLDM_FWUP;
+	header.command = PLDM_QUERY_DOWNSTREAM_IDENTIFIERS;
+	rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_init(buf, PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES,
+			      msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_insert(buf, data_transfer_handle);
+	// Data correctness has been verified, cast it to 1-byte data directly.
+	pldm_msgbuf_insert(buf, (uint8_t)transfer_operation_flag);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_TESTING
+int decode_query_downstream_identifiers_resp(
+	const struct pldm_msg *msg, size_t payload_length,
+	struct pldm_query_downstream_identifiers_resp *resp_data,
+	struct variable_field *downstream_devices)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc = PLDM_ERROR;
+
+	if (msg == NULL || resp_data == NULL || downstream_devices == NULL ||
+	    !payload_length) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
+			      msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
+	if (rc) {
+		return rc;
+	}
+	if (PLDM_SUCCESS != resp_data->completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length < PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
+	pldm_msgbuf_extract(buf, resp_data->transfer_flag);
+
+	rc = pldm_msgbuf_extract(buf, resp_data->downstream_devices_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
+	rc = pldm_msgbuf_span_required(buf,
+				       resp_data->downstream_devices_length,
+				       (void **)&downstream_devices->ptr);
+	if (rc) {
+		return rc;
+	}
+	downstream_devices->length = resp_data->downstream_devices_length;
+
+	return pldm_msgbuf_destroy(buf);
+}
+
 LIBPLDM_ABI_STABLE
 int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
 			      uint16_t num_of_comp,