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/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@
+