dcmi: asset-tag: Implement the Get Asset Tag command

Change-Id: Ic2fb1e707174ece63fbb758bf1422c2c4d95723b
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/dcmihandler.cpp b/dcmihandler.cpp
index c7497f0..5b83ac8 100644
--- a/dcmihandler.cpp
+++ b/dcmihandler.cpp
@@ -107,12 +107,92 @@
 
 } // namespace dcmi
 
+ipmi_ret_t getAssetTag(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 dcmi::GetAssetTagRequest*>
+                   (request);
+    std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
+    auto responseData = reinterpret_cast<dcmi::GetAssetTagResponse*>
+            (outPayload.data());
+
+    if (requestData->groupID != dcmi::groupExtId)
+    {
+        *data_len = 0;
+        return IPMI_CC_INVALID_FIELD_REQUEST;
+    }
+
+    // Verify offset to read and number of bytes to read are not exceeding the
+    // range.
+    if ((requestData->offset > dcmi::assetTagMaxOffset) ||
+        (requestData->bytes > dcmi::maxBytes) ||
+        ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
+    {
+        *data_len = 0;
+        return IPMI_CC_PARM_OUT_OF_RANGE;
+    }
+
+    std::string assetTag;
+
+    try
+    {
+        assetTag = dcmi::readAssetTag();
+    }
+    catch (InternalFailure& e)
+    {
+        *data_len = 0;
+        return IPMI_CC_UNSPECIFIED_ERROR;
+    }
+
+    responseData->groupID = dcmi::groupExtId;
+
+    // Return if the asset tag is not populated.
+    if (!assetTag.size())
+    {
+        responseData->tagLength = 0;
+        memcpy(response, outPayload.data(), outPayload.size());
+        *data_len = outPayload.size();
+        return IPMI_CC_OK;
+    }
+
+    // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
+    // Get Asset Tag command.
+    if (assetTag.size() > dcmi::assetTagMaxSize)
+    {
+        assetTag.resize(dcmi::assetTagMaxSize);
+    }
+
+    // If the requested offset is beyond the asset tag size.
+    if (requestData->offset >= assetTag.size())
+    {
+        *data_len = 0;
+        return IPMI_CC_PARM_OUT_OF_RANGE;
+    }
+
+    auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
+
+    responseData->tagLength = assetTag.size();
+
+    memcpy(response, outPayload.data(), outPayload.size());
+    memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
+           returnData.data(), returnData.size());
+    *data_len = outPayload.size() + returnData.size();
+
+    return IPMI_CC_OK;
+}
+
 void register_netfn_dcmi_functions()
 {
     // <Get Power Limit>
     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_POWER);
     ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_POWER, NULL, ipmi_dcmi_get_power_limit,
                            PRIVILEGE_USER);
+
+    // <Get Asset Tag>
+    printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_ASSET_TAG);
+    ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_ASSET_TAG, NULL, getAssetTag,
+                           PRIVILEGE_USER);
     return;
 }
 // 956379
diff --git a/dcmihandler.hpp b/dcmihandler.hpp
index dfe1d4e..f2369a0 100644
--- a/dcmihandler.hpp
+++ b/dcmihandler.hpp
@@ -10,6 +10,7 @@
 {
     // Get capability bits
     IPMI_CMD_DCMI_GET_POWER = 0x03,
+    IPMI_CMD_DCMI_GET_ASSET_TAG = 0x06,
 };
 
 namespace dcmi
@@ -30,6 +31,33 @@
 
 } //namespace assettag
 
+static constexpr auto groupExtId = 0xDC;
+
+static constexpr auto assetTagMaxOffset = 62;
+static constexpr auto assetTagMaxSize = 63;
+static constexpr auto maxBytes = 16;
+
+/** @struct GetAssetTagRequest
+ *
+ *  DCMI payload for Get Asset Tag command request.
+ */
+struct GetAssetTagRequest
+{
+    uint8_t groupID;            //!< Group extension identification.
+    uint8_t offset;             //!< Offset to read.
+    uint8_t bytes;              //!< Number of bytes to read.
+} __attribute__((packed));
+
+/** @struct GetAssetTagResponse
+ *
+ *  DCMI payload for Get Asset Tag command response.
+ */
+struct GetAssetTagResponse
+{
+    uint8_t groupID;            //!< Group extension identification.
+    uint8_t tagLength;          //!< Total asset tag length.
+} __attribute__((packed));
+
 /** @brief Read the object tree to fetch the object path that implemented the
  *         Asset tag interface.
  *
diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
index d921145..98353c2 100644
--- a/host-ipmid-whitelist.conf
+++ b/host-ipmid-whitelist.conf
@@ -25,3 +25,4 @@
 0x0C:0x02    //<Transport>:<Get LAN Configuration Parameters>
 0x2C:0x00    //<Group Extension>:<Group Extension Command>
 0x2C:0x03    //<Group Extension>:<Get Power Limit>
+0x2C:0x06    //<Group Extension>:<Get Asset Tag>