user_layer: Add get/set user payload access.

IPMI Spec reference: Section 24.6, 24.7.
Support is added to get/set user access details for the
unreserved, supported payload types defined by Spec.
SOL is the only unreserved, supported payload currently.
If support is needed for unreserved std/oem payload
types in future, they can be enabled with minor source code
changes to this implementation.

All payload types are packed in a JSON object
"payload_enabled" in ipmi_user.json file.

Tested-by:
1. For user 8 in channel 3, Enable SOL payload.

   // Command - (channel 3 is of LAN channel type)
   ipmitool  -I lanplus...raw 0x06 0x4C 3 0x8 0x02 0 0 0
   // Verify it with Get User Payload Access Command
   ipmitool  -I lanplus...raw 0x06 0x4D 3 8
   02 00 00 00 // Response

2. Disable SOL payload.

   // Command
   ipmitool  -I lanplus...raw 0x06 0x4C 3 0x48 0x02 0 0x00 0
   // Verify it with Get User Payload Access Command
   ipmitool  -I lanplus...raw 0x06 0x4D 3 8
   00 00 00 00 // Response

3. Enable unsupported payload stdPayload7.

   // Command
   ipmitool  -I lanplus...raw 0x06 0x4C 3 0x8 0x80 0 0 0
   Error: Invalid data field in request // Response

Change-Id: Idc57b04a747e55666407d928d8b2169223501e5b
Signed-off-by: Saravanan Palanisamy <saravanan.palanisamy@linux.intel.com>
diff --git a/user_channel/usercommands.cpp b/user_channel/usercommands.cpp
index 5bdbbd3..50fb52b 100644
--- a/user_channel/usercommands.cpp
+++ b/user_channel/usercommands.cpp
@@ -37,6 +37,8 @@
 static constexpr uint8_t testPassword = 0x03;
 static constexpr uint8_t passwordKeySize20 = 1;
 static constexpr uint8_t passwordKeySize16 = 0;
+static constexpr uint8_t enableOperation = 0x00;
+static constexpr uint8_t disableOperation = 0x01;
 
 /** @struct SetUserNameReq
  *
@@ -485,6 +487,188 @@
         rmcp, rmcpp, reserved5, oemID, oemAuxillary);
 }
 
+/** @brief implements the set user payload access command.
+ *  @param ctx - IPMI context pointer (for channel)
+ *  @param channel - channel number (4 bits)
+ *  @param reserved1 - skip 4 bits
+ *  @param userId - user id (6 bits)
+ *  @param operation - access ENABLE /DISABLE. (2 bits)
+ *  @param stdPayload0 - IPMI - reserved. (1 bit)
+ *  @param stdPayload1 - SOL.             (1 bit)
+ *  @param stdPayload2 -                  (1 bit)
+ *  @param stdPayload3 -                  (1 bit)
+ *  @param stdPayload4 -                  (1 bit)
+ *  @param stdPayload5 -                  (1 bit)
+ *  @param stdPayload6 -                  (1 bit)
+ *  @param stdPayload7 -                  (1 bit)
+ *  @param stdPayloadEnables2Reserved -   (8 bits)
+ *  @param oemPayload0 -                  (1 bit)
+ *  @param oemPayload1 -                  (1 bit)
+ *  @param oemPayload2 -                  (1 bit)
+ *  @param oemPayload3 -                  (1 bit)
+ *  @param oemPayload4 -                  (1 bit)
+ *  @param oemPayload5 -                  (1 bit)
+ *  @param oemPayload6 -                  (1 bit)
+ *  @param oemPayload7 -                  (1 bit)
+ *  @param oemPayloadEnables2Reserved -   (8 bits)
+ *
+ *  @returns IPMI completion code
+ */
+ipmi::RspType<> ipmiSetUserPayloadAccess(
+    ipmi::Context::ptr ctx,
+
+    uint4_t channel, uint4_t reserved,
+
+    uint6_t userId, uint2_t operation,
+
+    bool stdPayload0ipmiReserved, bool stdPayload1SOL, bool stdPayload2,
+    bool stdPayload3, bool stdPayload4, bool stdPayload5, bool stdPayload6,
+    bool stdPayload7,
+
+    uint8_t stdPayloadEnables2Reserved,
+
+    bool oemPayload0, bool oemPayload1, bool oemPayload2, bool oemPayload3,
+    bool oemPayload4, bool oemPayload5, bool oemPayload6, bool oemPayload7,
+
+    uint8_t oemPayloadEnables2Reserved)
+{
+    // Validate the reserved args. Only SOL payload is supported as on date.
+    if (reserved || stdPayload0ipmiReserved || stdPayload2 || stdPayload3 ||
+        stdPayload4 || stdPayload5 || stdPayload6 || stdPayload7 ||
+        oemPayload0 || oemPayload1 || oemPayload2 || oemPayload3 ||
+        oemPayload4 || oemPayload5 || oemPayload6 || oemPayload7 ||
+        stdPayloadEnables2Reserved || oemPayloadEnables2Reserved)
+    {
+        return ipmi::responseInvalidFieldRequest();
+    }
+
+    auto chNum =
+        convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
+    if ((operation != enableOperation && operation != disableOperation) ||
+        (!isValidChannel(chNum)) ||
+        (getChannelSessionSupport(chNum) == EChannelSessSupported::none))
+    {
+        return ipmi::responseInvalidFieldRequest();
+    }
+
+    if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
+    {
+        return ipmi::responseParmOutOfRange();
+    }
+
+    PayloadAccess payloadAccess = {0};
+    payloadAccess.stdPayloadEnables1[1] = stdPayload1SOL;
+
+    return ipmi::response(ipmiUserSetUserPayloadAccess(
+        chNum, static_cast<uint8_t>(operation), static_cast<uint8_t>(userId),
+        payloadAccess));
+}
+
+/** @brief implements the get user payload access command
+ *  This command returns information about user payload enable settings
+ *  that were set using the 'Set User Payload Access' Command.
+ *
+ *  @param ctx - IPMI context pointer (for channel)
+ *  @param channel - channel number
+ *  @param reserved1 - skip 4 bits
+ *  @param userId - user id
+ *  @param reserved2 - skip 2 bits
+ *
+ *  @returns IPMI completion code plus response data
+ *   - stdPayload0ipmiReserved - IPMI payload (reserved).
+ *   - stdPayload1SOL - SOL payload
+ *   - stdPayload2
+ *   - stdPayload3
+ *   - stdPayload4
+ *   - stdPayload5
+ *   - stdPayload6
+ *   - stdPayload7
+
+ *   - stdPayloadEnables2Reserved - Reserved.
+
+ *   - oemPayload0
+ *   - oemPayload1
+ *   - oemPayload2
+ *   - oemPayload3
+ *   - oemPayload4
+ *   - oemPayload5
+ *   - oemPayload6
+ *   - oemPayload7
+
+ *  - oemPayloadEnables2Reserved - Reserved
+ */
+ipmi::RspType<bool, // stdPayload0ipmiReserved
+              bool, // stdPayload1SOL
+              bool, // stdPayload2
+              bool, // stdPayload3
+              bool, // stdPayload4
+              bool, // stdPayload5
+              bool, // stdPayload6
+              bool, // stdPayload7
+
+              uint8_t, // stdPayloadEnables2Reserved
+
+              bool, // oemPayload0
+              bool, // oemPayload1
+              bool, // oemPayload2
+              bool, // oemPayload3
+              bool, // oemPayload4
+              bool, // oemPayload5
+              bool, // oemPayload6
+              bool, // oemPayload7
+
+              uint8_t // oemPayloadEnables2Reserved
+              >
+    ipmiGetUserPayloadAccess(ipmi::Context::ptr ctx,
+
+                             uint4_t channel, uint4_t reserved1,
+
+                             uint6_t userId, uint2_t reserved2)
+{
+    uint8_t chNum =
+        convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
+    if (reserved1 != 0 || reserved2 != 0 || (!isValidChannel(chNum)) ||
+        (getChannelSessionSupport(chNum) == EChannelSessSupported::none))
+    {
+        return ipmi::responseInvalidFieldRequest();
+    }
+    if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
+    {
+        return ipmi::responseParmOutOfRange();
+    }
+
+    ipmi::Cc retStatus;
+    PayloadAccess payloadAccess = {};
+    retStatus = ipmiUserGetUserPayloadAccess(
+        chNum, static_cast<uint8_t>(userId), payloadAccess);
+    if (retStatus != IPMI_CC_OK)
+    {
+        return ipmi::response(retStatus);
+    }
+    constexpr uint8_t res8bits = 0;
+    return ipmi::responseSuccess(payloadAccess.stdPayloadEnables1.test(0),
+                                 payloadAccess.stdPayloadEnables1.test(1),
+                                 payloadAccess.stdPayloadEnables1.test(2),
+                                 payloadAccess.stdPayloadEnables1.test(3),
+                                 payloadAccess.stdPayloadEnables1.test(4),
+                                 payloadAccess.stdPayloadEnables1.test(5),
+                                 payloadAccess.stdPayloadEnables1.test(6),
+                                 payloadAccess.stdPayloadEnables1.test(7),
+
+                                 res8bits,
+
+                                 payloadAccess.oemPayloadEnables1.test(0),
+                                 payloadAccess.oemPayloadEnables1.test(1),
+                                 payloadAccess.oemPayloadEnables1.test(2),
+                                 payloadAccess.oemPayloadEnables1.test(3),
+                                 payloadAccess.oemPayloadEnables1.test(4),
+                                 payloadAccess.oemPayloadEnables1.test(5),
+                                 payloadAccess.oemPayloadEnables1.test(6),
+                                 payloadAccess.oemPayloadEnables1.test(7),
+
+                                 res8bits);
+}
+
 void registerUserIpmiFunctions() __attribute__((constructor));
 void registerUserIpmiFunctions()
 {
@@ -510,6 +694,15 @@
                           ipmi::app::cmdGetChannelAuthCapabilities,
                           ipmi::Privilege::Callback,
                           ipmiGetChannelAuthenticationCapabilities);
+
+    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
+                          ipmi::app::cmdSetUserPayloadAccess,
+                          ipmi::Privilege::Admin, ipmiSetUserPayloadAccess);
+
+    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
+                          ipmi::app::cmdGetUserPayloadAccess,
+                          ipmi::Privilege::Operator, ipmiGetUserPayloadAccess);
+
     return;
 }
 } // namespace ipmi