msgbuf: Add copy API

pldm_msgbuf_copy API allows copy of data from one msg buffer
to another. This was done earlier with a pldm_msgbuf_extract()
followed by pldm_msgbuf_insert().

Change-Id: I159792f726916761894aefb0a8795f1f0dc84114
Signed-off-by: Varsha Kaverappa <vkaverap@in.ibm.com>
diff --git a/src/msgbuf.h b/src/msgbuf.h
index f81eb13..1f71e4c 100644
--- a/src/msgbuf.h
+++ b/src/msgbuf.h
@@ -884,6 +884,62 @@
 
 	return PLDM_SUCCESS;
 }
+
+/**
+ * @brief pldm_msgbuf copy data between two msg buffers
+ *
+ * @param[inout] src - pldm_msgbuf for source from where value should be copied
+ * @param[inout] dst - destination of copy from source
+ * @param[in] size - size of data to be copied
+ * @param[in] description - description of data copied
+ *
+ * @return PLDM_SUCCESS if buffer accesses were in-bounds,
+ * PLDM_ERROR_INVALID_LENGTH otherwise.
+ * PLDM_ERROR_INVALID_DATA if input is invalid
+ */
+#define pldm_msgbuf_copy(dst, src, type, name)                                 \
+	pldm__msgbuf_copy(dst, src, sizeof(type), #name)
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+static inline int pldm__msgbuf_copy(struct pldm_msgbuf *dst,
+				    struct pldm_msgbuf *src, size_t size,
+				    const char *description)
+{
+	if (!src || !src->cursor || !dst || !dst->cursor || !description) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+#if INTMAX_MAX < SIZE_MAX
+	if (size > INTMAX_MAX) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+#endif
+
+	if (src->remaining < INTMAX_MIN + (intmax_t)size) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	if (dst->remaining < INTMAX_MIN + (intmax_t)size) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	src->remaining -= (intmax_t)size;
+	assert(src->remaining >= 0);
+	if (src->remaining < 0) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	dst->remaining -= (intmax_t)size;
+	assert(dst->remaining >= 0);
+	if (dst->remaining < 0) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	memcpy(dst->cursor, src->cursor, size);
+	src->cursor += size;
+	dst->cursor += size;
+
+	return PLDM_SUCCESS;
+}
 #ifdef __cplusplus
 }
 #endif
diff --git a/tests/msgbuf.cpp b/tests/msgbuf.cpp
index fecf514..cfe7914 100644
--- a/tests/msgbuf.cpp
+++ b/tests/msgbuf.cpp
@@ -944,3 +944,56 @@
     EXPECT_EQ(pldm_msgbuf_destroy(ctxExtract), PLDM_SUCCESS);
     EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_SUCCESS);
 }
+
+TEST(msgbuf, pldm_msgbuf_copy_good)
+{
+    struct pldm_msgbuf _src;
+    struct pldm_msgbuf* src = &_src;
+    uint16_t buf[1] = {htole16(0x5aa5)};
+
+    ASSERT_EQ(pldm_msgbuf_init(src, sizeof(buf), buf, sizeof(buf)),
+              PLDM_SUCCESS);
+
+    struct pldm_msgbuf _dst;
+    struct pldm_msgbuf* dst = &_dst;
+    uint16_t checkVal = 0;
+    uint8_t buf1[sizeof(buf)] = {};
+
+    ASSERT_EQ(pldm_msgbuf_init(dst, sizeof(buf1), buf1, sizeof(buf1)),
+              PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_copy(dst, src, buf[0], name), PLDM_SUCCESS);
+
+    ASSERT_EQ(pldm_msgbuf_init(dst, sizeof(buf1), buf1, sizeof(buf1)),
+              PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_extract_uint16(dst, &checkVal), PLDM_SUCCESS);
+
+    EXPECT_EQ(buf[0], checkVal);
+    EXPECT_EQ(pldm_msgbuf_destroy(src), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(dst), PLDM_SUCCESS);
+}
+
+TEST(msgbuf, pldm_msgbuf_copy_bad)
+{
+    struct pldm_msgbuf _src;
+    struct pldm_msgbuf* src = &_src;
+    struct pldm_msgbuf _dst;
+    struct pldm_msgbuf* dst = &_dst;
+    uint8_t buf[1] = {sizeof(uint8_t)};
+    uint8_t buf1[1] = {sizeof(uint16_t)};
+    uint16_t value = 8;
+
+    EXPECT_EQ(pldm_msgbuf_copy(dst, NULL, buf[0], name),
+              PLDM_ERROR_INVALID_DATA);
+    EXPECT_EQ(pldm_msgbuf_copy(NULL, src, buf[0], name),
+              PLDM_ERROR_INVALID_DATA);
+
+    ASSERT_EQ(pldm_msgbuf_init(src, 0, buf, sizeof(buf)), PLDM_SUCCESS);
+    ASSERT_EQ(pldm_msgbuf_init(dst, 0, buf1, sizeof(buf1)), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_copy(dst, src, value, name),
+              PLDM_ERROR_INVALID_LENGTH);
+
+    ASSERT_EQ(pldm_msgbuf_init(src, 0, buf1, sizeof(buf1)), PLDM_SUCCESS);
+    ASSERT_EQ(pldm_msgbuf_init(dst, 0, buf, sizeof(buf)), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_copy(dst, src, value, name),
+              PLDM_ERROR_INVALID_LENGTH);
+}