Open Session Request/Response Implementation

Change-Id: I2726f52c8eb331575677fb0e6a52943a2c5f5865
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/command/open_session.cpp b/command/open_session.cpp
new file mode 100644
index 0000000..0c17d3d
--- /dev/null
+++ b/command/open_session.cpp
@@ -0,0 +1,93 @@
+#include "open_session.hpp"
+
+#include <iostream>
+
+#include "comm_module.hpp"
+#include "endian.hpp"
+#include "main.hpp"
+
+namespace command
+{
+
+std::vector<uint8_t> openSession(std::vector<uint8_t>& inPayload,
+                                 const message::Handler& handler)
+{
+    std::cout << ">> openSession\n";
+
+    std::vector<uint8_t> outPayload(sizeof(OpenSessionResponse));
+    auto request = reinterpret_cast<OpenSessionRequest*>(inPayload.data());
+    auto response = reinterpret_cast<OpenSessionResponse*>(outPayload.data());
+
+    // Check for valid Authentication Algorithms
+    if (request->authAlgo != static_cast<uint8_t>
+        (cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA1))
+    {
+        response->status_code =
+            static_cast<uint8_t>(RAKP_ReturnCode::INVALID_AUTH_ALGO);
+        return outPayload;
+    }
+
+    // Check for valid Integrity Algorithms
+    if (request->intAlgo != 0)
+    {
+        response->status_code =
+            static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_ALGO);
+        return outPayload;
+    }
+
+    // Check for valid Confidentiality Algorithms
+    if (request->confAlgo != 0)
+    {
+        response->status_code =
+            static_cast<uint8_t>(RAKP_ReturnCode::INVALID_CONF_ALGO);
+        return outPayload;
+    }
+
+    std::shared_ptr<session::Session> session;
+    try
+    {
+        // Start an IPMI session
+        session = (std::get<session::Manager&>(singletonPool).startSession(
+                  endian::from_ipmi<>(request->remoteConsoleSessionID),
+                  static_cast<session::Privilege>(request->maxPrivLevel),
+                  static_cast<cipher::rakp_auth::Algorithms>(request->authAlgo)
+                  )).lock();
+    }
+    catch (std::exception& e)
+    {
+        std::cerr << e.what() << "\n";
+        response->status_code = static_cast<uint8_t>
+                                (RAKP_ReturnCode::INSUFFICIENT_RESOURCE);
+        std::cerr << "openSession : Problem opening a session\n";
+        return outPayload;
+    }
+
+    response->messageTag = request->messageTag;
+    response->status_code = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
+    response->maxPrivLevel = static_cast<uint8_t>(session->curPrivLevel);
+    response->remoteConsoleSessionID = request->remoteConsoleSessionID;
+    response->managedSystemSessionID = endian::to_ipmi<>
+                                       (session->getBMCSessionID());
+
+    response->authPayload = request->authPayload ;
+    response->authPayloadLen = request->authPayloadLen ;
+    response->authAlgo = request->authAlgo;
+
+    response->intPayload = request->intPayload ;
+    response->intPayloadLen = request->intPayloadLen ;
+    response->intAlgo = request->intAlgo;
+
+    response->confPayload = request->confPayload ;
+    response->confPayloadLen = request->confPayloadLen ;
+    response->confAlgo = request->confAlgo;
+
+    session->updateLastTransactionTime();
+
+    // Session state is Setup in progress
+    session->state = session::State::SETUP_IN_PROGRESS;
+
+    std::cout << "<< openSession\n";
+    return outPayload;
+}
+
+} // namespace command
diff --git a/command/open_session.hpp b/command/open_session.hpp
new file mode 100644
index 0000000..f5111d2
--- /dev/null
+++ b/command/open_session.hpp
@@ -0,0 +1,180 @@
+#pragma once
+
+#include <vector>
+
+#include "message_handler.hpp"
+
+namespace command
+{
+
+/*
+ * @ struct OpenSessionRequest
+ *
+ * IPMI Payload for RMCP+ Open Session Request
+ */
+struct OpenSessionRequest
+{
+    uint8_t messageTag;  // Message tag from request buffer
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+    uint8_t maxPrivLevel : 4 ;// Requested maximum privilege level
+    uint8_t reserved1 : 4;  // Reserved for future definition
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+    uint8_t reserved1 : 4;  // Reserved for future definition
+    uint8_t maxPrivLevel : 4 ;// Requested maximum privilege level
+
+#endif
+
+    uint16_t reserved2;
+    uint32_t remoteConsoleSessionID ;
+
+    uint8_t authPayload ;
+    uint16_t  reserved3;
+    uint8_t  authPayloadLen;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+    uint8_t authAlgo : 6;
+    uint8_t reserved4 : 2;
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+    uint8_t reserved4 : 2;
+    uint8_t authAlgo : 6;
+#endif
+
+    uint8_t reserved5;
+    uint16_t reserved6;
+
+    uint8_t intPayload;
+    uint16_t reserved7;
+    uint8_t  intPayloadLen;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+    uint8_t intAlgo : 6;
+    uint8_t reserved8 : 2;
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+    uint8_t reserved8 : 2;
+    uint8_t intAlgo : 6;
+#endif
+
+    uint8_t reserved9;
+    uint16_t reserved10;
+
+    uint8_t confPayload;
+    uint16_t reserved11;
+    uint8_t  confPayloadLen;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+    uint8_t confAlgo : 6;
+    uint8_t reserved12 : 2;
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+    uint8_t reserved12 : 2;
+    uint8_t confAlgo : 6;
+#endif
+
+    uint8_t reserved13;
+    uint16_t reserved14;
+} __attribute__((packed));
+
+/*
+ * @ struct OpenSessionResponse
+ *
+ * IPMI Payload for RMCP+ Open Session Response
+ */
+struct OpenSessionResponse
+{
+    uint8_t messageTag;
+    uint8_t status_code;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+    uint8_t maxPrivLevel : 4;
+    uint8_t reserved1 : 4;
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+    uint8_t reserved1 : 4;
+    uint8_t maxPrivLevel : 4;
+#endif
+
+    uint8_t reserved2;
+    uint32_t remoteConsoleSessionID;
+    uint32_t managedSystemSessionID;
+
+    uint8_t authPayload;
+    uint16_t reserved3;
+    uint8_t authPayloadLen;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+    uint8_t authAlgo : 6;
+    uint8_t reserved4 : 2;
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+    uint8_t reserved4 : 2;
+    uint8_t authAlgo : 6;
+#endif
+
+    uint8_t reserved5;
+    uint16_t reserved6;
+
+    uint8_t intPayload;
+    uint16_t reserved7;
+    uint8_t  intPayloadLen;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+    uint8_t intAlgo : 6;
+    uint8_t reserved8 : 2;
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+    uint8_t reserved8 : 2;
+    uint8_t intAlgo : 6;
+
+#endif
+
+    uint8_t reserved9;
+    uint16_t reserved10;
+
+    uint8_t confPayload;
+    uint16_t reserved11;
+    uint8_t  confPayloadLen;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+    uint8_t confAlgo : 6;
+    uint8_t reserved12 : 2;
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+    uint8_t reserved12 : 2;
+    uint8_t confAlgo : 6;
+#endif
+
+    uint8_t reserved13;
+    uint16_t reserved14;
+} __attribute__((packed));
+
+/*
+ * @brief RMCP+ Open Session Request, RMCP+ Open Session Response
+ *
+ * The RMCP+ Open Session request and response messages are used to enable a
+ * remote console to discover what Cipher Suite(s) can be used for establishing
+ * a session at a requested maximum privilege level. These messages are also
+ * used for transferring the sessions IDs that the remote console and BMC wish
+ *  to for the session once it’s been activated, and to track each party during
+ *  the exchange of messages used for establishing the 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> openSession(std::vector<uint8_t>& inPayload,
+                                 const message::Handler& handler);
+
+} // namespace command