Implement discovery commands

This commit does the following
- Implements the GetPLDMTypes and GetPLDMCommands commands. These are
  commands that need to be handled by a PLDM device as part of the
  initial PLDM discovery.
- Sets up the build infrastructure: separate libraries for PLDM
  encode/decode libs and the PLDM responder.

Change-Id: I65fa222d2a681c473f579c8e30d84faaf94fe754
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..406e1bc
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = libpldm libpldmresponder test
diff --git a/bootstrap.sh b/bootstrap.sh
new file mode 100755
index 0000000..50b75b7
--- /dev/null
+++ b/bootstrap.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+AUTOCONF_FILES="Makefile.in aclocal.m4 ar-lib autom4te.cache compile \
+        config.guess config.h.in config.sub configure depcomp install-sh \
+        ltmain.sh missing *libtool test-driver"
+
+case $1 in
+    clean)
+        test -f Makefile && make maintainer-clean
+        for file in ${AUTOCONF_FILES}; do
+            find -name "$file" | xargs -r rm -rf
+        done
+        exit 0
+        ;;
+esac
+
+autoreconf -i
+echo 'Run "./configure ${CONFIGURE_FLAGS} && make"'
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..b192d79
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,47 @@
+# Initialization
+AC_PREREQ([2.69])
+AC_INIT([pldm], [1.0],
+        [https://github.com/openbmc/pldm/issues])
+AC_LANG([C++])
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([subdir-objects -Wall -Werror foreign dist-xz])
+AM_SILENT_RULES([yes])
+
+# Checks for programs.
+AC_PROG_CXX
+AC_PROG_CC
+AM_PROG_AR
+AC_PROG_INSTALL
+
+# Checks for typedefs, structures, and compiler characteristics.
+AX_CXX_COMPILE_STDCXX([17], [noext], [mandatory])
+AX_APPEND_COMPILE_FLAGS([-Wall -Werror], [CXXFLAGS])
+
+# For linking
+LT_INIT
+
+# Check/set gtest specific functions.
+AX_PTHREAD([GTEST_CPPFLAGS="-DGTEST_HAS_PTHREAD=1"],[GTEST_CPPFLAGS="-DGTEST_HAS_PTHREAD=0"])
+AC_SUBST(GTEST_CPPFLAGS)
+AC_ARG_ENABLE([oe-sdk],
+    AS_HELP_STRING([--enable-oe-sdk], [Link testcases absolutely against OE SDK so they can be ran within it.])
+)
+AC_ARG_VAR(OECORE_TARGET_SYSROOT,
+    [Path to the OE SDK SYSROOT])
+AS_IF([test "x$enable_oe_sdk" == "xyes"],
+    AS_IF([test "x$OECORE_TARGET_SYSROOT" == "x"],
+          AC_MSG_ERROR([OECORE_TARGET_SYSROOT must be set with --enable-oe-sdk])
+    )
+    AC_MSG_NOTICE([Enabling OE-SDK at $OECORE_TARGET_SYSROOT])
+    [
+        testcase_flags="-Wl,-rpath,\${OECORE_TARGET_SYSROOT}/lib"
+        testcase_flags="${testcase_flags} -Wl,-rpath,\${OECORE_TARGET_SYSROOT}/usr/lib"
+        testcase_flags="${testcase_flags} -Wl,-dynamic-linker,`find \${OECORE_TARGET_SYSROOT}/lib/ld-*.so | sort -r -n | head -n1`"
+    ]
+    AC_SUBST([OESDK_TESTCASE_FLAGS], [$testcase_flags])
+)
+
+# Create configured output
+AC_CONFIG_FILES([Makefile libpldm/Makefile libpldmresponder/Makefile test/Makefile])
+AC_CONFIG_FILES([libpldm/libpldm.pc])
+AC_OUTPUT
diff --git a/libpldm/Makefile.am b/libpldm/Makefile.am
new file mode 100644
index 0000000..3ff405b
--- /dev/null
+++ b/libpldm/Makefile.am
@@ -0,0 +1,12 @@
+nobase_include_HEADERS = \
+	base.h
+
+libpldm_LTLIBRARIES = libpldm.la
+libpldmdir = ${libdir}
+libpldm_la_SOURCES = \
+	base.c
+libpldm_la_LDFLAGS = \
+        -version-info 1:0:0 -shared
+
+pkgconfiglibdir = ${libdir}/pkgconfig
+pkgconfiglib_DATA = libpldm.pc
diff --git a/libpldm/base.c b/libpldm/base.c
new file mode 100644
index 0000000..db32ca4
--- /dev/null
+++ b/libpldm/base.c
@@ -0,0 +1,104 @@
+#include <endian.h>
+#include <string.h>
+
+#include "base.h"
+
+int encode_get_types_req(uint8_t instance_id, struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+int encode_get_commands_req(uint8_t instance_id, uint8_t type,
+			    struct pldm_version version, struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	uint8_t *dst = msg->body.payload;
+	memcpy(dst, &type, sizeof(type));
+	dst += sizeof(type);
+	memcpy(dst, &version, sizeof(version));
+
+	return PLDM_SUCCESS;
+}
+
+int encode_get_types_resp(uint8_t instance_id, uint8_t completion_code,
+			  const uint8_t *types, struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	msg->body.payload[0] = completion_code;
+	if (msg->body.payload[0] == PLDM_SUCCESS) {
+		if (types == NULL) {
+			return PLDM_ERROR_INVALID_DATA;
+		}
+		uint8_t *dst = msg->body.payload + sizeof(msg->body.payload[0]);
+		memcpy(dst, types, PLDM_MAX_TYPES / 8);
+	}
+
+	return PLDM_SUCCESS;
+}
+
+int decode_get_commands_req(const struct pldm_msg_payload *msg, uint8_t *type,
+			    struct pldm_version *version)
+{
+	if (msg == NULL || type == NULL || version == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	const uint8_t *start = msg->payload;
+	*type = *start;
+	memcpy(version, (struct pldm_version *)(start + sizeof(*type)),
+	       sizeof(*version));
+
+	return PLDM_SUCCESS;
+}
+
+int encode_get_commands_resp(uint8_t instance_id, uint8_t completion_code,
+			     const uint8_t *commands, struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	msg->body.payload[0] = completion_code;
+	if (msg->body.payload[0] == PLDM_SUCCESS) {
+		if (commands == NULL) {
+			return PLDM_ERROR_INVALID_DATA;
+		}
+		uint8_t *dst = msg->body.payload + sizeof(msg->body.payload[0]);
+		memcpy(dst, commands, PLDM_MAX_CMDS_PER_TYPE / 8);
+	}
+
+	return PLDM_SUCCESS;
+}
+
+int decode_get_types_resp(const struct pldm_msg_payload *msg, uint8_t *types)
+{
+	if (msg == NULL || types == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	const uint8_t *src = msg->payload + sizeof(uint8_t);
+	memcpy(types, src, PLDM_MAX_TYPES / 8);
+
+	return PLDM_SUCCESS;
+}
+
+int decode_get_commands_resp(const struct pldm_msg_payload *msg,
+			     uint8_t *commands)
+{
+	if (msg == NULL || commands == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	const uint8_t *src = msg->payload + sizeof(uint8_t);
+	memcpy(commands, src, PLDM_MAX_CMDS_PER_TYPE / 8);
+
+	return PLDM_SUCCESS;
+}
diff --git a/libpldm/base.h b/libpldm/base.h
new file mode 100644
index 0000000..29b2c87
--- /dev/null
+++ b/libpldm/base.h
@@ -0,0 +1,199 @@
+#ifndef BASE_H
+#define BASE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <asm/byteorder.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/** @brief PLDM Types
+ */
+enum pldm_supported_types {
+	PLDM_BASE = 0x00,
+};
+
+/** @brief PLDM Commands
+ */
+enum pldm_supported_commands {
+	PLDM_GET_PLDM_TYPES = 0x4,
+	PLDM_GET_PLDM_COMMANDS = 0x5
+};
+
+/** @brief PLDM base codes
+ */
+enum pldm_completion_codes {
+	PLDM_SUCCESS = 0x00,
+	PLDM_ERROR = 0x01,
+	PLDM_ERROR_INVALID_DATA = 0x02,
+	PLDM_ERROR_INVALID_LENGTH = 0x03,
+	PLDM_ERROR_NOT_READY = 0x04,
+	PLDM_ERROR_UNSUPPORTED_PLDM_CMD = 0x05,
+	PLDM_ERROR_INVALID_PLDM_TYPE = 0x20
+};
+
+#define PLDM_MAX_TYPES 64
+#define PLDM_MAX_CMDS_PER_TYPE 256
+
+/* Message payload lengths */
+#define PLDM_GET_COMMANDS_REQ_BYTES 5
+
+/* Response lengths are inclusive of completion code */
+#define PLDM_GET_TYPES_RESP_BYTES 9
+#define PLDM_GET_COMMANDS_RESP_BYTES 33
+
+/** @struct pldm_msg_hdr
+ *
+ * Structure representing PLDM message header fields
+ */
+struct pldm_msg_hdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	uint8_t instance_id : 5; //!< Instance ID
+	uint8_t reserved : 1;    //!< Reserved
+	uint8_t datagram : 1;    //!< Datagram bit
+	uint8_t request : 1;     //!< Request bit
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	uint8_t request : 1;     //!< Request bit
+	uint8_t datagram : 1;    //!< Datagram bit
+	uint8_t reserved : 1;    //!< Reserved
+	uint8_t instance_id : 5; //!< Instance ID
+#endif
+
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	uint8_t type : 6;       //!< PLDM type
+	uint8_t header_ver : 2; //!< Header version
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	uint8_t header_ver : 2;  //!< Header version
+	uint8_t type : 6;	//!< PLDM type
+#endif
+	uint8_t command; //!< PLDM command code
+} __attribute__((packed));
+
+/** @struct pldm_msg_payload
+ *
+ * Structure representing PLDM message payload
+ */
+struct pldm_msg_payload {
+	uint8_t *payload;      //!< Pointer to PLDM message payload
+	size_t payload_length; //!< PLDM message payload's length in bytes
+} __attribute__((packed));
+
+/** @struct pldm_msg
+ *
+ * Structure representing PLDM message
+ */
+struct pldm_msg {
+	struct pldm_msg_hdr hdr;      //!< PLDM message header
+	struct pldm_msg_payload body; //!< PLDM message payload
+} __attribute__((packed));
+
+/** @struct pldm_version
+ *
+ * Structure representing PLDM ver32 type
+ */
+struct pldm_version {
+	uint8_t major;
+	uint8_t minor;
+	uint8_t update;
+	uint8_t alpha;
+} __attribute__((packed));
+
+/* Requester */
+
+/* GetPLDMTypes */
+
+/** @brief Create a PLDM request message for GetPLDMTypes
+ *
+ *  @param[in] instance_id - Message's instance id
+ *  @param[in,out] msg - Message will be written to this
+ *  @return pldm_completion_codes
+ *  @note  Caller is responsible for memory alloc and dealloc of param
+ *         'msg.body.payload'
+ */
+int encode_get_types_req(uint8_t instance_id, struct pldm_msg *msg);
+
+/** @brief Decode a GetPLDMTypes response message
+ *
+ *  @param[in] msg - Response message payload
+ *  @param[out] types - pointer to array uint8_t[8] containing supported
+ *              types (MAX_TYPES/8) = 8), as per DSP0240
+ *  @return pldm_completion_codes
+ */
+int decode_get_types_resp(const struct pldm_msg_payload *msg, uint8_t *types);
+
+/* GetPLDMCommands */
+
+/** @brief Create a PLDM request message for GetPLDMCommands
+ *
+ *  @param[in] instance_id - Message's instance id
+ *  @param[in] type - PLDM Type
+ *  @param[in] version - Version for PLDM Type
+ *  @param[in,out] msg - Message will be written to this
+ *  @return pldm_completion_codes
+ *  @note  Caller is responsible for memory alloc and dealloc of param
+ *         'msg.body.payload'
+ */
+int encode_get_commands_req(uint8_t instance_id, uint8_t type,
+			    struct pldm_version version, struct pldm_msg *msg);
+
+/** @brief Decode a GetPLDMCommands response message
+ *
+ *  @param[in] msg - Response message payload
+ *  @param[in] commands - pointer to array uint8_t[32] containing supported
+ *             commands (PLDM_MAX_CMDS_PER_TYPE/8) = 32), as per DSP0240
+ *  @return pldm_completion_codes
+ */
+int decode_get_commands_resp(const struct pldm_msg_payload *msg,
+			     uint8_t *commands);
+
+/* Responder */
+
+/* GetPLDMTypes */
+
+/** @brief Create a PLDM response message for GetPLDMTypes
+ *
+ *  @param[in] instance_id - Message's instance id
+ *  @param[in] completion_code - PLDM completion code
+ *  @param[in] types - pointer to array uint8_t[8] containing supported
+ *             types (MAX_TYPES/8) = 8), as per DSP0240
+ *  @param[in,out] msg - Message will be written to this
+ *  @return pldm_completion_codes
+ *  @note  Caller is responsible for memory alloc and dealloc of param
+ *         'msg.body.payload'
+ */
+int encode_get_types_resp(uint8_t instance_id, uint8_t completion_code,
+			  const uint8_t *types, struct pldm_msg *msg);
+
+/* GetPLDMCommands */
+
+/** @brief Decode GetPLDMCommands' request data
+ *
+ *  @param[in] msg - Request message payload
+ *  @param[out] type - PLDM Type
+ *  @param[out] version - Version for PLDM Type
+ *  @return pldm_completion_codes
+ */
+int decode_get_commands_req(const struct pldm_msg_payload *msg, uint8_t *type,
+			    struct pldm_version *version);
+
+/** @brief Create a PLDM response message for GetPLDMCommands
+ *
+ *  @param[in] instance_id - Message's instance id
+ *  @param[in] completion_code - PLDM completion code
+ *  @param[in] commands - pointer to array uint8_t[32] containing supported
+ *             commands (PLDM_MAX_CMDS_PER_TYPE/8) = 32), as per DSP0240
+ *  @param[in,out] msg - Message will be written to this
+ *  @return pldm_completion_codes
+ *  @note  Caller is responsible for memory alloc and dealloc of param
+ *         'msg.body.payload'
+ */
+int encode_get_commands_resp(uint8_t instance_id, uint8_t completion_code,
+			     const uint8_t *commands, struct pldm_msg *msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BASE_H */
diff --git a/libpldm/libpldm.pc.in b/libpldm/libpldm.pc.in
new file mode 100644
index 0000000..d6bdcf8
--- /dev/null
+++ b/libpldm/libpldm.pc.in
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libpldm
+Description: PLDM encode/decode C library
+URL: https://github.com/openbmc/pldm/libpldm
+Version: @VERSION@
+Requires: @AX_PACKAGE_REQUIRES@
+Requires.private: @AX_PACKAGE_REQUIRES_PRIVATE@
+Libs: -L@libdir@ -lpldm
+Cflags: -I@includedir@
+
diff --git a/libpldmresponder/Makefile.am b/libpldmresponder/Makefile.am
new file mode 100644
index 0000000..f308394
--- /dev/null
+++ b/libpldmresponder/Makefile.am
@@ -0,0 +1,8 @@
+libpldmresponder_LTLIBRARIES = libpldmresponder.la
+libpldmresponderdir = ${libdir}
+libpldmresponder_la_SOURCES = \
+	base.cpp
+libpldmresponder_la_LIBADD = \
+	../libpldm/libpldm.la
+libpldmresponder_la_LDFLAGS = \
+	-version-info 1:0:0 -shared
diff --git a/libpldmresponder/base.cpp b/libpldmresponder/base.cpp
new file mode 100644
index 0000000..f3bb8f4
--- /dev/null
+++ b/libpldmresponder/base.cpp
@@ -0,0 +1,70 @@
+#include "libpldm/base.h"
+
+#include "base.hpp"
+
+#include <array>
+#include <map>
+#include <stdexcept>
+#include <vector>
+
+namespace pldm
+{
+namespace responder
+{
+
+using Cmd = std::vector<uint8_t>;
+
+static const std::map<Type, Cmd> capabilities{
+    {PLDM_BASE, {PLDM_GET_PLDM_TYPES, PLDM_GET_PLDM_COMMANDS}}};
+
+void getPLDMTypes(const pldm_msg_payload* request, pldm_msg* response)
+{
+    // DSP0240 has this as a bitfield8[N], where N = 0 to 7
+    std::array<uint8_t, 8> types{};
+    for (const auto& type : capabilities)
+    {
+        auto index = type.first / 8;
+        // <Type Number> = <Array Index> * 8 + <bit position>
+        auto bit = type.first - (index * 8);
+        types[index] |= 1 << bit;
+    }
+
+    encode_get_types_resp(0, PLDM_SUCCESS, types.data(), response);
+}
+
+void getPLDMCommands(const pldm_msg_payload* request, pldm_msg* response)
+{
+    pldm_version version{};
+    Type type;
+
+    if (request->payload_length != (sizeof(version) + sizeof(type)))
+    {
+        encode_get_commands_resp(0, PLDM_ERROR_INVALID_LENGTH, nullptr,
+                                 response);
+        return;
+    }
+
+    decode_get_commands_req(request, &type, &version);
+
+    // DSP0240 has this as a bitfield8[N], where N = 0 to 31
+    std::array<uint8_t, 32> cmds{};
+    if (capabilities.find(type) == capabilities.end())
+    {
+        encode_get_commands_resp(0, PLDM_ERROR_INVALID_PLDM_TYPE, nullptr,
+                                 response);
+        return;
+    }
+
+    for (const auto& cmd : capabilities.at(type))
+    {
+        auto index = cmd / 8;
+        // <Type Number> = <Array Index> * 8 + <bit position>
+        auto bit = cmd - (index * 8);
+        cmds[index] |= 1 << bit;
+    }
+
+    encode_get_commands_resp(0, PLDM_SUCCESS, cmds.data(), response);
+}
+
+} // namespace responder
+} // namespace pldm
diff --git a/libpldmresponder/base.hpp b/libpldmresponder/base.hpp
new file mode 100644
index 0000000..e4351d4
--- /dev/null
+++ b/libpldmresponder/base.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "libpldm/base.h"
+
+namespace pldm
+{
+
+using Type = uint8_t;
+
+namespace responder
+{
+
+/** @brief Handler for getPLDMTypes
+ *
+ *  @param[in] request - Request message payload
+ *  @param[out] response - Response message written here
+ */
+void getPLDMTypes(const pldm_msg_payload* request, pldm_msg* response);
+
+/** @brief Handler for getPLDMCommands
+ *
+ *  @param[in] request - Request message payload
+ *  @param[out] response - Response message written here
+ */
+void getPLDMCommands(const pldm_msg_payload* request, pldm_msg* response);
+
+} // namespace responder
+} // namespace pldm
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..82101f7
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,35 @@
+AM_CPPFLAGS = -I$(top_srcdir)
+
+TESTS = $(check_PROGRAMS)
+
+check_PROGRAMS = \
+	libpldm_base_test \
+	libpldmresponder_base_test
+
+test_cppflags = \
+	-Igtest \
+	$(GTEST_CPPFLAGS) \
+	$(AM_CPPFLAGS)
+
+test_cxxflags = \
+	$(PTHREAD_CFLAGS)
+
+test_ldflags = \
+	-lgtest_main \
+	-lgtest \
+	$(PTHREAD_LIBS) \
+	$(OESDK_TESTCASE_FLAGS)
+
+libpldm_base_test_CPPFLAGS = $(test_cppflags)
+libpldm_base_test_CXXFLAGS = $(test_cxxflags)
+libpldm_base_test_LDFLAGS = $(test_ldflags)
+libpldm_base_test_LDADD = $(top_builddir)/libpldm/base.o
+libpldm_base_test_SOURCES = libpldm_base_test.cpp
+
+libpldmresponder_base_test_CPPFLAGS = $(test_cppflags)
+libpldmresponder_base_test_CXXFLAGS = $(test_cxxflags)
+libpldmresponder_base_test_LDFLAGS = $(test_ldflags)
+libpldmresponder_base_test_LDADD = \
+	$(top_builddir)/libpldm/base.o \
+	$(top_builddir)/libpldmresponder/base.o
+libpldmresponder_base_test_SOURCES = libpldmresponder_base_test.cpp
diff --git a/test/libpldm_base_test.cpp b/test/libpldm_base_test.cpp
new file mode 100644
index 0000000..3be7ddd
--- /dev/null
+++ b/test/libpldm_base_test.cpp
@@ -0,0 +1,121 @@
+#include <string.h>
+
+#include <array>
+
+#include "libpldm/base.h"
+
+#include <gtest/gtest.h>
+
+TEST(GetPLDMCommands, testEncodeRequest)
+{
+    uint8_t pldmType = 0x05;
+    pldm_version version{0xFF, 0xFF, 0xFF, 0xFF};
+    std::array<uint8_t, PLDM_GET_COMMANDS_REQ_BYTES> requestMsg{};
+    pldm_msg request{};
+    request.body.payload = requestMsg.data();
+    request.body.payload_length = requestMsg.size();
+
+    auto rc = encode_get_commands_req(0, pldmType, version, &request);
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(0, memcmp(request.body.payload, &pldmType, sizeof(pldmType)));
+    ASSERT_EQ(0, memcmp(request.body.payload + sizeof(pldmType), &version,
+                        sizeof(version)));
+}
+
+TEST(GetPLDMCommands, testDecodeRequest)
+{
+    uint8_t pldmType = 0x05;
+    pldm_version version{0xFF, 0xFF, 0xFF, 0xFF};
+    uint8_t pldmTypeOut{};
+    pldm_version versionOut{0xFF, 0xFF, 0xFF, 0xFF};
+    std::array<uint8_t, PLDM_GET_COMMANDS_REQ_BYTES> requestMsg{};
+    pldm_msg_payload request{};
+    request.payload = requestMsg.data();
+    request.payload_length = requestMsg.size();
+
+    memcpy(request.payload, &pldmType, sizeof(pldmType));
+    memcpy(request.payload + sizeof(pldmType), &version, sizeof(version));
+    auto rc = decode_get_commands_req(&request, &pldmTypeOut, &versionOut);
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(pldmTypeOut, pldmType);
+    ASSERT_EQ(0, memcmp(&versionOut, &version, sizeof(version)));
+}
+
+TEST(GetPLDMCommands, testEncodeResponse)
+{
+    uint8_t completionCode = 0;
+    std::array<uint8_t, PLDM_GET_COMMANDS_RESP_BYTES> responseMsg{};
+    pldm_msg response{};
+    response.body.payload = responseMsg.data();
+    response.body.payload_length = responseMsg.size();
+    std::array<uint8_t, PLDM_MAX_CMDS_PER_TYPE / 8> commands{};
+    commands[0] = 1;
+    commands[1] = 2;
+    commands[2] = 3;
+
+    auto rc =
+        encode_get_commands_resp(0, PLDM_SUCCESS, commands.data(), &response);
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(completionCode, response.body.payload[0]);
+    ASSERT_EQ(1, response.body.payload[1]);
+    ASSERT_EQ(2, response.body.payload[2]);
+    ASSERT_EQ(3, response.body.payload[3]);
+}
+
+TEST(GetPLDMTypes, testEncodeResponse)
+{
+    uint8_t completionCode = 0;
+    std::array<uint8_t, PLDM_GET_TYPES_RESP_BYTES> responseMsg{};
+    pldm_msg response{};
+    response.body.payload = responseMsg.data();
+    response.body.payload_length = responseMsg.size();
+    std::array<uint8_t, PLDM_MAX_TYPES / 8> types{};
+    types[0] = 1;
+    types[1] = 2;
+    types[2] = 3;
+
+    auto rc = encode_get_types_resp(0, PLDM_SUCCESS, types.data(), &response);
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(completionCode, response.body.payload[0]);
+    ASSERT_EQ(1, response.body.payload[1]);
+    ASSERT_EQ(2, response.body.payload[2]);
+    ASSERT_EQ(3, response.body.payload[3]);
+}
+
+TEST(GetPLDMTypes, testDecodeResponse)
+{
+    std::array<uint8_t, PLDM_GET_TYPES_RESP_BYTES> responseMsg{};
+    pldm_msg_payload response{};
+    response.payload = responseMsg.data();
+    response.payload_length = responseMsg.size();
+    response.payload[1] = 1;
+    response.payload[2] = 2;
+    response.payload[3] = 3;
+    std::array<uint8_t, PLDM_MAX_TYPES / 8> outTypes{};
+
+    auto rc = decode_get_types_resp(&response, outTypes.data());
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(response.payload[1], outTypes[0]);
+    ASSERT_EQ(response.payload[2], outTypes[1]);
+    ASSERT_EQ(response.payload[3], outTypes[2]);
+}
+
+TEST(GetPLDMCommands, testDecodeResponse)
+{
+    std::array<uint8_t, PLDM_MAX_CMDS_PER_TYPE> responseMsg{};
+    pldm_msg_payload response{};
+    response.payload = responseMsg.data();
+    response.payload_length = responseMsg.size();
+    response.payload[1] = 1;
+    response.payload[2] = 2;
+    response.payload[3] = 3;
+    std::array<uint8_t, PLDM_MAX_CMDS_PER_TYPE / 8> outTypes{};
+
+    auto rc = decode_get_commands_resp(&response, outTypes.data());
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(response.payload[1], outTypes[0]);
+    ASSERT_EQ(response.payload[2], outTypes[1]);
+    ASSERT_EQ(response.payload[3], outTypes[2]);
+}
diff --git a/test/libpldmresponder_base_test.cpp b/test/libpldmresponder_base_test.cpp
new file mode 100644
index 0000000..2bd6ebd
--- /dev/null
+++ b/test/libpldmresponder_base_test.cpp
@@ -0,0 +1,59 @@
+#include "libpldmresponder/base.hpp"
+
+#include <string.h>
+
+#include <array>
+
+#include "libpldm/base.h"
+
+#include <gtest/gtest.h>
+
+using namespace pldm::responder;
+
+TEST(GetPLDMTypes, testGoodRequest)
+{
+    pldm_msg_payload request{};
+    pldm_msg response{};
+    std::array<uint8_t, PLDM_GET_TYPES_RESP_BYTES> responseMsg{};
+    response.body.payload = responseMsg.data();
+    response.body.payload_length = responseMsg.size();
+    getPLDMTypes(&request, &response);
+    // Only base type supported at the moment
+    ASSERT_EQ(response.body.payload[0], 0);
+    ASSERT_EQ(response.body.payload[1], 1);
+    ASSERT_EQ(response.body.payload[2], 0);
+}
+
+TEST(GetPLDMCommands, testGoodRequest)
+{
+    // Only base type supported at the moment, and commands -
+    // GetPLDMTypes, GetPLDMCommands
+    pldm_msg response{};
+    std::array<uint8_t, PLDM_GET_COMMANDS_RESP_BYTES> responseMsg{};
+    response.body.payload = responseMsg.data();
+    response.body.payload_length = responseMsg.size();
+    pldm_msg_payload request{};
+    std::array<uint8_t, 5> requestPayload{};
+    request.payload = requestPayload.data();
+    request.payload_length = requestPayload.size();
+    getPLDMCommands(&request, &response);
+    ASSERT_EQ(response.body.payload[0], 0);
+    ASSERT_EQ(response.body.payload[1], 48); // 48 = 0b110000
+    ASSERT_EQ(response.body.payload[2], 0);
+}
+
+TEST(GetPLDMCommands, testBadRequest)
+{
+    pldm_msg response{};
+    std::array<uint8_t, PLDM_GET_COMMANDS_RESP_BYTES> responseMsg{};
+    response.body.payload = responseMsg.data();
+    response.body.payload_length = responseMsg.size();
+    pldm_msg_payload request{};
+    std::array<uint8_t, 5> requestPayload{};
+
+    request.payload = requestPayload.data();
+    request.payload[0] = 0xFF;
+    request.payload_length = requestPayload.size();
+    getPLDMCommands(&request, &response);
+    ASSERT_EQ(response.body.payload[0], PLDM_ERROR_INVALID_PLDM_TYPE);
+}