Add command handler for Activate payload command.

Change-Id: I95d2d82409dabde7139871c7d62d5b5106c1c4d8
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index ad42d8d..cd4682e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -48,7 +48,9 @@
 	sol/sol_manager.cpp \
 	sol/sol_context.cpp \
 	command/sol_cmds.hpp \
-	command/sol_cmds.cpp
+	command/sol_cmds.cpp \
+	command/payload_cmds.hpp \
+	command/payload_cmds.cpp
 
 netipmid_CPPFLAGS = -DNET_IPMID_LIB_PATH=\"/usr/lib/net-ipmid/\"
 netipmid_LDFLAGS = $(SYSTEMD_LIBS) $(CRYPTO_LIBS) $(libmapper_LIBS) $(PHOSPHOR_LOGGING_LIBS) $(LIBADD_DLOPEN) -export-dynamic
diff --git a/command/payload_cmds.cpp b/command/payload_cmds.cpp
new file mode 100644
index 0000000..02c854a
--- /dev/null
+++ b/command/payload_cmds.cpp
@@ -0,0 +1,86 @@
+#include <host-ipmid/ipmid-api.h>
+#include <phosphor-logging/log.hpp>
+#include "main.hpp"
+#include "payload_cmds.hpp"
+#include "sol/sol_manager.hpp"
+#include "sol_cmds.hpp"
+
+namespace sol
+{
+
+namespace command
+{
+
+using namespace phosphor::logging;
+
+std::vector<uint8_t> activatePayload(std::vector<uint8_t>& inPayload,
+                                     const message::Handler& handler)
+{
+    std::vector<uint8_t> outPayload(sizeof(ActivatePayloadResponse));
+    auto request = reinterpret_cast<ActivatePayloadRequest*>(inPayload.data());
+    auto response = reinterpret_cast<ActivatePayloadResponse*>
+                    (outPayload.data());
+
+    response->completionCode = IPMI_CC_OK;
+
+    // SOL is the payload currently supported for activation.
+    if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType)
+    {
+        response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
+        return outPayload;
+    }
+
+    // Only one instance of SOL is currently supported.
+    if (request->payloadInstance != 1)
+    {
+        response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
+        return outPayload;
+    }
+
+    auto session = (std::get<session::Manager&>(singletonPool).getSession(
+                       handler.sessionID)).lock();
+
+    if (!request->encryption && session->isCryptAlgoEnabled())
+    {
+        response->completionCode = IPMI_CC_PAYLOAD_WITHOUT_ENCRYPTION;
+        return outPayload;
+    }
+
+    auto status = std::get<sol::Manager&>(singletonPool).isPayloadActive(
+            request->payloadInstance);
+    if (status)
+    {
+        response->completionCode = IPMI_CC_PAYLOAD_ALREADY_ACTIVE;
+        return outPayload;
+    }
+
+    // Set the current command's socket channel to the session
+    handler.setChannelInSession();
+
+    // Start the SOL payload
+    try
+    {
+        std::get<sol::Manager&>(singletonPool).startPayloadInstance(
+                request->payloadInstance,
+                handler.sessionID);
+    }
+    catch (std::exception& e)
+    {
+        log<level::ERR>(e.what());
+        response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
+        return outPayload;
+    }
+
+    response->inPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE);
+    response->outPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE);
+    response->portNum = endian::to_ipmi<uint16_t>(IPMI_STD_PORT);
+
+    // VLAN addressing is not used
+    response->vlanNum = 0xFFFF;
+
+    return outPayload;
+}
+
+} // namespace command
+
+} // namespace sol
diff --git a/command/payload_cmds.hpp b/command/payload_cmds.hpp
new file mode 100644
index 0000000..ed6ca92
--- /dev/null
+++ b/command/payload_cmds.hpp
@@ -0,0 +1,116 @@
+#pragma once
+
+#include <vector>
+#include "message_handler.hpp"
+
+namespace sol
+{
+
+namespace command
+{
+
+constexpr uint8_t IPMI_CC_PAYLOAD_ALREADY_ACTIVE = 0x80;
+constexpr uint8_t IPMI_CC_PAYLOAD_TYPE_DISABLED = 0x81;
+constexpr uint8_t IPMI_CC_PAYLOAD_ACTIVATION_LIMIT = 0x82;
+constexpr uint8_t IPMI_CC_PAYLOAD_WITH_ENCRYPTION = 0x83;
+constexpr uint8_t IPMI_CC_PAYLOAD_WITHOUT_ENCRYPTION = 0x84;
+
+/** @struct ActivatePayloadRequest
+ *
+ *  IPMI payload for Activate Payload command request.
+ */
+struct ActivatePayloadRequest
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+    uint8_t payloadType : 6;        //!< Payload type.
+    uint8_t reserved1 : 2;          //!< Reserved.
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+    uint8_t reserved1 : 2;          //!< Payload type.
+    uint8_t payloadType : 6;        //!< Payload type.
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+    uint8_t payloadInstance : 4;    //!< Payload instance.
+    uint8_t reserved2 : 4;          //!< Reserved.
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+    uint8_t reserved2 : 4;          //!< Reserved.
+    uint8_t payloadInstance : 4;    //!< Payload instance.
+#endif
+
+    /** @brief The following Auxiliary Request Data applies only for payload
+     *         SOL only.
+     */
+#if BYTE_ORDER == LITTLE_ENDIAN
+    uint8_t reserved4 : 1;  //!< Reserved.
+    uint8_t handshake : 1;  //!< SOL startup handshake.
+    uint8_t alert : 2;      //!< Shared serial alert behavior.
+    uint8_t reserved3 : 1;  //!< Reserved.
+    uint8_t testMode : 1;   //!< Test mode.
+    uint8_t auth : 1;       //!< If true, activate payload with authentication.
+    uint8_t encryption : 1; //!< If true, activate payload with encryption.
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+    uint8_t encryption : 1; //!< If true, activate payload with encryption.
+    uint8_t auth : 1;       //!< If true, activate payload with authentication.
+    uint8_t testMode : 1;   //!< Test mode.
+    uint8_t reserved3 : 1;  //!< Reserved.
+    uint8_t alert : 2;      //!< Shared serial alert behavior.
+    uint8_t handshake : 1;  //!< SOL startup handshake.
+    uint8_t reserved4 : 1;  //!< Reserved.
+#endif
+
+    uint8_t reserved5;      //!< Reserved.
+    uint8_t reserved6;      //!< Reserved.
+    uint8_t reserved7;      //!< Reserved.
+} __attribute__((packed));
+
+/** @struct ActivatePayloadResponse
+ *
+ *  IPMI payload for Activate Payload command response.
+ */
+struct ActivatePayloadResponse
+{
+    uint8_t completionCode;     //!< Completion code.
+    uint8_t reserved1;          //!< Reserved.
+    uint8_t reserved2;          //!< Reserved.
+    uint8_t reserved3;          //!< Reserved.
+
+    // Test Mode
+#if BYTE_ORDER == LITTLE_ENDIAN
+    uint8_t testMode : 1;       //!< Test mode.
+    uint8_t reserved4 : 7;      //!< Reserved.
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+    uint8_t reserved4 : 7;      //!< Reserved.
+    uint8_t testMode : 1;       //!< Test mode.
+#endif
+
+    uint16_t inPayloadSize;     //!< Inbound payload size
+    uint16_t outPayloadSize;    //!< Outbound payload size.
+    uint16_t portNum;           //!< Payload UDP port number.
+    uint16_t vlanNum;           //!< Payload VLAN number.
+} __attribute__((packed));
+
+/** @brief Activate Payload Command.
+ *
+ *  This command is used for activating and deactivating a payload type under a
+ *  given IPMI session. The UDP Port number for SOL is the same as the port that
+ *  was used to establish the IPMI session.
+ *
+ *  @param[in] inPayload - Request data for the command.
+ *  @param[in] handler - Reference to the message handler.
+ *
+ *  @return Response data for the command
+ */
+std::vector<uint8_t> activatePayload(std::vector<uint8_t>& inPayload,
+                                     const message::Handler& handler);
+
+} // namespace command
+
+} // namespace sol