Implement Get channel access command

The get channel access command is implemented to support the set
channel access command. The set channel access command is used to
apply the network settings. Before the set channel access is issued
ipmitool issues get channel access command to get all the fields and
then copy into the buffer for set channel access. This would enable
the following ipmitool command.

ipmitool lan set 1 access on

There is no backend support for these settings and values are
hardcoded in the command implementation.

Resolves openbmc/openbmc#1565

Change-Id: I6c7b2ca7971155b90914ab5b68ab3038bfaba185
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/apphandler.cpp b/apphandler.cpp
index 5145a0a..8340922 100644
--- a/apphandler.cpp
+++ b/apphandler.cpp
@@ -10,6 +10,7 @@
 #include <systemd/sd-bus.h>
 #include <mapper.h>
 #include <array>
+#include <vector>
 #include <arpa/inet.h>
 #include "transporthandler.hpp"
 
@@ -710,6 +711,50 @@
     return rc;
 }
 
+ipmi_ret_t getChannelAccess(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)
+{
+    auto requestData = reinterpret_cast<const GetChannelAccessRequest*>
+                   (request);
+    std::vector<uint8_t> outPayload(sizeof(GetChannelAccessResponse));
+    auto responseData = reinterpret_cast<GetChannelAccessResponse*>
+            (outPayload.data());
+
+    // Channel 1 is arbitrarily assigned to ETH0 channel
+    constexpr auto channelOne = 0x01;
+
+    /*
+     * The value Eh is used as a way to identify the current channel that
+     * the command is being received from.
+     */
+    constexpr auto channelE = 0x0E;
+
+    if (requestData->channelNumber != channelOne &&
+        requestData->channelNumber != channelE)
+    {
+        *data_len = 0;
+        return IPMI_CC_INVALID_FIELD_REQUEST;
+    }
+
+    /*
+     * [7:6] - reserved
+     * [5]   - 1b = Alerting disabled
+     * [4]   - 1b = per message authentication disabled
+     * [3]   - 0b = User level authentication enabled
+     * [2:0] - 2h = always available
+     */
+    constexpr auto channelSetting = 0x32;
+
+    responseData->settings = channelSetting;
+    //Defaulting the channel privilege to administrator level.
+    responseData->privilegeLimit = PRIVILEGE_ADMIN;
+
+    *data_len = outPayload.size();
+    memcpy(response, outPayload.data(), *data_len);
+
+    return IPMI_CC_OK;
+}
 
 // ATTENTION: This ipmi function is very hardcoded on purpose
 // OpenBMC does not fully support IPMI.  This command is useful
@@ -816,6 +861,11 @@
     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_CHAN_ACCESS, NULL,
                                     ipmi_set_channel_access, PRIVILEGE_ADMIN);
 
+    // <Get Channel Access>
+    printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS);
+    ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS, NULL,
+                           getChannelAccess, PRIVILEGE_USER);
+
     // <Get Channel Info Command>
     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_GET_CHAN_INFO);
     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_INFO, NULL, ipmi_app_channel_info,
diff --git a/apphandler.h b/apphandler.h
index ec7d4b0..497b24b 100644
--- a/apphandler.h
+++ b/apphandler.h
@@ -15,7 +15,28 @@
     IPMI_CMD_SET_WD                 = 0x24,
     IPMI_CMD_GET_CAP_BIT            = 0x36,
     IPMI_CMD_SET_CHAN_ACCESS        = 0x40,
+    IPMI_CMD_GET_CHANNEL_ACCESS     = 0x41,
     IPMI_CMD_GET_CHAN_INFO          = 0x42,
 };
 
+/** @struct GetChannelAccessRequest
+ *
+ *  IPMI payload for Get Channel access command request.
+ */
+struct GetChannelAccessRequest
+{
+    uint8_t channelNumber;      //!< Channel number.
+    uint8_t volatileSetting;    //!< Get non-volatile or the volatile setting.
+} __attribute__((packed));
+
+/** @struct GetChannelAccessResponse
+ *
+ *  IPMI payload for Get Channel access command response.
+ */
+struct GetChannelAccessResponse
+{
+    uint8_t settings;          //!< Channel settings.
+    uint8_t privilegeLimit;    //!< Channel privilege level limit.
+} __attribute__((packed));
+
 #endif