Implement RMCP+ cipher parameters in Get LAN Config parameters

Change-Id: Ic78965be94b1ba31149a05a29c1a768f06b492e4
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/transporthandler.cpp b/transporthandler.cpp
index 96a462d..b33dc7d 100644
--- a/transporthandler.cpp
+++ b/transporthandler.cpp
@@ -1,4 +1,5 @@
 #include <chrono>
+#include <fstream>
 #include <stdio.h>
 #include <string.h>
 #include <stdint.h>
@@ -6,6 +7,7 @@
 #include <string>
 #include <experimental/filesystem>
 
+#include "app/channel.hpp"
 #include "host-ipmid/ipmid-api.h"
 #include "ipmid.hpp"
 #include "timer.hpp"
@@ -357,6 +359,40 @@
     return rc;
 }
 
+namespace cipher
+{
+
+std::vector<uint8_t> getCipherList()
+{
+    std::vector<uint8_t> cipherList;
+
+    std::ifstream jsonFile(configFile);
+    if (!jsonFile.is_open())
+    {
+        log<level::ERR>("Channel Cipher suites file not found");
+        elog<InternalFailure>();
+    }
+
+    auto data = Json::parse(jsonFile, nullptr, false);
+    if (data.is_discarded())
+    {
+        log<level::ERR>("Parsing channel cipher suites JSON failed");
+        elog<InternalFailure>();
+    }
+
+    // Byte 1 is reserved
+    cipherList.push_back(0x00);
+
+    for (const auto& record : data)
+    {
+        cipherList.push_back(record.value(cipher, 0));
+    }
+
+    return cipherList;
+}
+
+} //namespace cipher
+
 ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
                               ipmi_request_t request, ipmi_response_t response,
                               ipmi_data_len_t data_len, ipmi_context_t context)
@@ -553,6 +589,22 @@
         return IPMI_CC_OK;
     }
 
+    static std::vector<uint8_t> cipherList;
+    static auto listInit = false;
+
+    if (!listInit)
+    {
+        try
+        {
+            cipherList = cipher::getCipherList();
+            listInit = true;
+        }
+        catch (const std::exception &e)
+        {
+            return IPMI_CC_UNSPECIFIED_ERROR;
+        }
+    }
+
     auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
     if (ethdevice.empty())
     {
@@ -628,6 +680,26 @@
             memcpy(response, &buff, *data_len);
         }
     }
+    else if (reqptr->parameter == CIPHER_SUITE_COUNT)
+    {
+        *(static_cast<uint8_t*>(response)) = current_revision;
+        // Byte 1 is reserved byte and does not indicate a cipher suite ID, so
+        // no of cipher suite entry count is one less than the size of the
+        // vector
+        auto count = static_cast<uint8_t>(cipherList.size() - 1);
+        *(static_cast<uint8_t*>(response) + 1) = count;
+        *data_len = sizeof(current_revision) + sizeof(count);
+    }
+    else if (reqptr->parameter == CIPHER_SUITE_ENTRIES)
+    {
+        *(static_cast<uint8_t*>(response)) = current_revision;
+        // Byte 1 is reserved
+        std::copy_n(cipherList.data(),
+                    cipherList.size(),
+                    static_cast<uint8_t*>(response) + 1);
+        *data_len = sizeof(current_revision) +
+                static_cast<uint8_t>(cipherList.size());
+    }
     else
     {
         log<level::ERR>("Unsupported parameter",
diff --git a/transporthandler.hpp b/transporthandler.hpp
index f440403..432bd68 100644
--- a/transporthandler.hpp
+++ b/transporthandler.hpp
@@ -26,6 +26,8 @@
 static const int LAN_PARM_SUBNET      = 6;
 static const int LAN_PARM_GATEWAY     = 12;
 static const int LAN_PARM_VLAN        = 20;
+static const int CIPHER_SUITE_COUNT   = 22;
+static const int CIPHER_SUITE_ENTRIES = 23;
 
 constexpr uint8_t SET_COMPLETE = 0;
 constexpr uint8_t SET_IN_PROGRESS = 1;