Update DCMI asset tag commands

DCMI asset tag commands were still using the old IPMI API and
blocking dbus calls. This updates them to use the new API and
yielding dbus calls.

Tested: 'ipmitool dcmi asset_tag' and ipmitool dcmi set_asset_tag'
        work the same as before

Change-Id: I0f6486fc3d9494628db12ddfe0afbd6afd967a91
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/dcmihandler.cpp b/dcmihandler.cpp
index 33749eb..e2c0167 100644
--- a/dcmihandler.cpp
+++ b/dcmihandler.cpp
@@ -60,6 +60,10 @@
 
 namespace dcmi
 {
+constexpr auto assetTagMaxOffset = 62;
+constexpr auto assetTagMaxSize = 63;
+constexpr auto maxBytes = 16;
+constexpr size_t maxCtrlIdStrLen = 63;
 
 // Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
 static const std::map<uint8_t, std::string> entityIdToName{
@@ -167,97 +171,56 @@
     return true;
 }
 
-void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
+std::optional<std::string> readAssetTag(ipmi::Context::ptr& ctx)
 {
-    static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
-    static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
-    static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
-    static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
-
-    sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
-    auto depth = 0;
-
-    auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
-                                          mapperIface, "GetSubTree");
-
-    mapperCall.append(inventoryRoot);
-    mapperCall.append(depth);
-    mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
-
-    try
-    {
-        auto mapperReply = bus.call(mapperCall);
-        mapperReply.read(objectTree);
-
-        if (objectTree.empty())
-        {
-            log<level::ERR>("AssetTag property is not populated");
-            elog<InternalFailure>();
-        }
-    }
-    catch (const std::exception& e)
-    {
-        log<level::ERR>("Error in mapper call", entry("ERROR=%s", e.what()));
-        elog<InternalFailure>();
-    }
-}
-
-std::string readAssetTag()
-{
-    sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
-    dcmi::assettag::ObjectTree objectTree;
-
     // Read the object tree with the inventory root to figure out the object
     // that has implemented the Asset tag interface.
-    readAssetTagObjectTree(objectTree);
-
-    auto method = bus.new_method_call(
-        (objectTree.begin()->second.begin()->first).c_str(),
-        (objectTree.begin()->first).c_str(), dcmi::propIntf, "Get");
-    method.append(dcmi::assetTagIntf);
-    method.append(dcmi::assetTagProp);
-
-    std::variant<std::string> assetTag;
-    try
+    ipmi::DbusObjectInfo objectInfo;
+    boost::system::error_code ec = getDbusObject(
+        ctx, dcmi::assetTagIntf, ipmi::sensor::inventoryRoot, "", objectInfo);
+    if (ec.value())
     {
-        auto reply = bus.call(method);
-        reply.read(assetTag);
-        return std::get<std::string>(assetTag);
+        return std::nullopt;
     }
-    catch (const std::exception& e)
+
+    std::string assetTag{};
+    ec = ipmi::getDbusProperty(ctx, objectInfo.second, objectInfo.first,
+                               dcmi::assetTagIntf, dcmi::assetTagProp,
+                               assetTag);
+    if (ec.value())
     {
         log<level::ERR>("Error in reading asset tag",
-                        entry("ERROR=%s", e.what()));
+                        entry("ERROR=%s", ec.message().c_str()));
         elog<InternalFailure>();
+        return std::nullopt;
     }
+
+    return assetTag;
 }
 
-void writeAssetTag(const std::string& assetTag)
+bool writeAssetTag(ipmi::Context::ptr& ctx, const std::string& assetTag)
 {
-    sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
-    dcmi::assettag::ObjectTree objectTree;
-
     // Read the object tree with the inventory root to figure out the object
     // that has implemented the Asset tag interface.
-    readAssetTagObjectTree(objectTree);
-
-    auto method = bus.new_method_call(
-        (objectTree.begin()->second.begin()->first).c_str(),
-        (objectTree.begin()->first).c_str(), dcmi::propIntf, "Set");
-    method.append(dcmi::assetTagIntf);
-    method.append(dcmi::assetTagProp);
-    method.append(std::variant<std::string>(assetTag));
-
-    try
+    ipmi::DbusObjectInfo objectInfo;
+    boost::system::error_code ec = getDbusObject(
+        ctx, dcmi::assetTagIntf, ipmi::sensor::inventoryRoot, "", objectInfo);
+    if (ec.value())
     {
-        auto reply = bus.call(method);
+        return false;
     }
-    catch (const std::exception& e)
+
+    ec = ipmi::setDbusProperty(ctx, objectInfo.second, objectInfo.first,
+                               dcmi::assetTagIntf, dcmi::assetTagProp,
+                               assetTag);
+    if (ec.value())
     {
         log<level::ERR>("Error in writing asset tag",
-                        entry("ERROR=%s", e.what()));
+                        entry("ERROR=%s", ec.message().c_str()));
         elog<InternalFailure>();
+        return false;
     }
+    return true;
 }
 
 std::string getHostName(void)
@@ -429,124 +392,92 @@
     return ipmi::responseSuccess();
 }
 
-ipmi_ret_t getAssetTag(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
-                       ipmi_response_t response, ipmi_data_len_t data_len,
-                       ipmi_context_t)
+ipmi::RspType<uint8_t,          // total tag length
+              std::vector<char> // tag data
+              >
+    getAssetTag(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count)
 {
-    auto requestData =
-        reinterpret_cast<const dcmi::GetAssetTagRequest*>(request);
-    std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
-    auto responseData =
-        reinterpret_cast<dcmi::GetAssetTagResponse*>(outPayload.data());
-
-    // 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))
+    // Verify offset to read and number of bytes to read are not exceeding
+    // the range.
+    if ((offset > dcmi::assetTagMaxOffset) || (count > dcmi::maxBytes) ||
+        ((offset + count) > dcmi::assetTagMaxSize))
     {
-        *data_len = 0;
-        return IPMI_CC_PARM_OUT_OF_RANGE;
+        return ipmi::responseParmOutOfRange();
     }
 
-    std::string assetTag;
-
-    try
+    std::optional<std::string> assetTagResp = dcmi::readAssetTag(ctx);
+    if (!assetTagResp)
     {
-        assetTag = dcmi::readAssetTag();
-    }
-    catch (const InternalFailure& e)
-    {
-        *data_len = 0;
-        return IPMI_CC_UNSPECIFIED_ERROR;
+        return ipmi::responseUnspecifiedError();
     }
 
-    // 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.
+    std::string& assetTag = assetTagResp.value();
+    // 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())
+    if (offset >= assetTag.size())
     {
-        *data_len = 0;
-        return IPMI_CC_PARM_OUT_OF_RANGE;
+        return ipmi::responseParmOutOfRange();
     }
 
-    auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
+    // silently truncate reads beyond the end of assetTag
+    if ((offset + count) >= assetTag.size())
+    {
+        count = assetTag.size() - offset;
+    }
 
-    responseData->tagLength = assetTag.size();
+    auto totalTagSize = static_cast<uint8_t>(assetTag.size());
+    std::vector<char> data{assetTag.begin() + offset,
+                           assetTag.begin() + offset + count};
 
-    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;
+    return ipmi::responseSuccess(totalTagSize, data);
 }
 
-ipmi_ret_t setAssetTag(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
-                       ipmi_response_t response, ipmi_data_len_t data_len,
-                       ipmi_context_t)
+ipmi::RspType<uint8_t // new asset tag length
+              >
+    setAssetTag(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count,
+                const std::vector<char>& data)
 {
-    auto requestData =
-        reinterpret_cast<const dcmi::SetAssetTagRequest*>(request);
-    std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
-    auto responseData =
-        reinterpret_cast<dcmi::SetAssetTagResponse*>(outPayload.data());
-
-    // 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))
+    // Verify offset to read and number of bytes to read are not exceeding
+    // the range.
+    if ((offset > dcmi::assetTagMaxOffset) || (count > dcmi::maxBytes) ||
+        ((offset + count) > dcmi::assetTagMaxSize))
     {
-        *data_len = 0;
-        return IPMI_CC_PARM_OUT_OF_RANGE;
+        return ipmi::responseParmOutOfRange();
+    }
+    if (data.size() != count)
+    {
+        return ipmi::responseReqDataLenInvalid();
     }
 
-    std::string assetTag;
-
-    try
+    std::optional<std::string> assetTagResp = dcmi::readAssetTag(ctx);
+    if (!assetTagResp)
     {
-        assetTag = dcmi::readAssetTag();
-
-        if (requestData->offset > assetTag.size())
-        {
-            *data_len = 0;
-            return IPMI_CC_PARM_OUT_OF_RANGE;
-        }
-
-        assetTag.replace(requestData->offset,
-                         assetTag.size() - requestData->offset,
-                         static_cast<const char*>(request) +
-                             sizeof(dcmi::SetAssetTagRequest),
-                         requestData->bytes);
-
-        dcmi::writeAssetTag(assetTag);
-
-        responseData->tagLength = assetTag.size();
-        memcpy(response, outPayload.data(), outPayload.size());
-        *data_len = outPayload.size();
-
-        return IPMI_CC_OK;
+        return ipmi::responseUnspecifiedError();
     }
-    catch (const InternalFailure& e)
+
+    std::string& assetTag = assetTagResp.value();
+
+    if (offset > assetTag.size())
     {
-        *data_len = 0;
-        return IPMI_CC_UNSPECIFIED_ERROR;
+        return ipmi::responseParmOutOfRange();
     }
+
+    // operation is to truncate at offset and append new data
+    assetTag.resize(offset);
+    assetTag.append(data.begin(), data.end());
+
+    if (!dcmi::writeAssetTag(ctx, assetTag))
+    {
+        return ipmi::responseUnspecifiedError();
+    }
+
+    auto totalTagSize = static_cast<uint8_t>(assetTag.size());
+    return ipmi::responseSuccess(totalTagSize);
 }
 
 ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
@@ -1406,14 +1337,14 @@
                          ipmi::Privilege::Operator, applyPowerLimit);
 
     // <Get Asset Tag>
-
-    ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG, NULL,
-                           getAssetTag, PRIVILEGE_USER);
+    registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
+                         ipmi::dcmi::cmdGetAssetTag, ipmi::Privilege::User,
+                         getAssetTag);
 
     // <Set Asset Tag>
-
-    ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG, NULL,
-                           setAssetTag, PRIVILEGE_OPERATOR);
+    registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
+                         ipmi::dcmi::cmdSetAssetTag, ipmi::Privilege::Operator,
+                         setAssetTag);
 
     // <Get Management Controller Identifier String>
 
diff --git a/dcmihandler.hpp b/dcmihandler.hpp
index f5c69c1..0a846be 100644
--- a/dcmihandler.hpp
+++ b/dcmihandler.hpp
@@ -19,9 +19,7 @@
     // Get capability bits
     GET_CAPABILITIES = 0x01,
     GET_POWER_READING = 0x02,
-    GET_ASSET_TAG = 0x06,
     GET_SENSOR_INFO = 0x07,
-    SET_ASSET_TAG = 0x08,
     GET_MGMNT_CTRL_ID_STR = 0x09,
     SET_MGMNT_CTRL_ID_STR = 0x0A,
     GET_TEMP_READINGS = 0x10,
@@ -59,16 +57,6 @@
 static constexpr auto gMaxSELEntriesMask = 0xFFF;
 static constexpr auto gByteBitSize = 8;
 
-namespace assettag
-{
-
-using ObjectPath = std::string;
-using Service = std::string;
-using Interfaces = std::vector<std::string>;
-using ObjectTree = std::map<ObjectPath, std::map<Service, Interfaces>>;
-
-} // namespace assettag
-
 namespace temp_readings
 {
 static constexpr auto maxDataSets = 8;
@@ -116,49 +104,6 @@
 
 static constexpr auto groupExtId = 0xDC;
 
-static constexpr auto assetTagMaxOffset = 62;
-static constexpr auto assetTagMaxSize = 63;
-static constexpr auto maxBytes = 16;
-static constexpr size_t maxCtrlIdStrLen = 63;
-
-/** @struct GetAssetTagRequest
- *
- *  DCMI payload for Get Asset Tag command request.
- */
-struct GetAssetTagRequest
-{
-    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 tagLength; //!< Total asset tag length.
-} __attribute__((packed));
-
-/** @struct SetAssetTagRequest
- *
- *  DCMI payload for Set Asset Tag command request.
- */
-struct SetAssetTagRequest
-{
-    uint8_t offset; //!< Offset to write.
-    uint8_t bytes;  //!< Number of bytes to write.
-} __attribute__((packed));
-
-/** @struct SetAssetTagResponse
- *
- *  DCMI payload for Set Asset Tag command response.
- */
-struct SetAssetTagResponse
-{
-    uint8_t tagLength; //!< Total asset tag length.
-} __attribute__((packed));
-
 /** @brief Check whether DCMI power management is supported
  *         in the DCMI Capabilities config file.
  *
@@ -166,28 +111,6 @@
  */
 bool isDCMIPowerMgmtSupported();
 
-/** @brief Read the object tree to fetch the object path that implemented the
- *         Asset tag interface.
- *
- *  @param[in,out] objectTree - object tree
- *
- *  @return On success return the object tree with the object path that
- *          implemented the AssetTag interface.
- */
-void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree);
-
-/** @brief Read the asset tag of the server
- *
- *  @return On success return the asset tag.
- */
-std::string readAssetTag();
-
-/** @brief Write the asset tag to the asset tag DBUS property
- *
- *  @param[in] assetTag - Asset Tag to be written to the property.
- */
-void writeAssetTag(const std::string& assetTag);
-
 /** @struct GetMgmntCtrlIdStrRequest
  *
  *  DCMI payload for Get Management Controller Identifier String cmd request.