Add Intel-specific IPMI sensor commands

Also includes SDR storage commands that are required to support
the 'ipmitool sensor list' command.

Change-Id: Id1830097d93882114085fce723f0b92367b2db48
Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
diff --git a/src/oemcommands.cpp b/src/oemcommands.cpp
index e6eddcc..6b38579 100644
--- a/src/oemcommands.cpp
+++ b/src/oemcommands.cpp
@@ -17,9 +17,9 @@
 #include <host-ipmid/ipmid-api.h>
 
 #include <array>
-#include <host-ipmid/utils.hpp>
 #include <iostream>
 #include <oemcommands.hpp>
+#include <phosphor-ipmi-host/utils.hpp>
 #include <phosphor-logging/log.hpp>
 #include <sdbusplus/bus.hpp>
 #include <sstream>
diff --git a/src/sensorcommands.cpp b/src/sensorcommands.cpp
new file mode 100644
index 0000000..3c1f050
--- /dev/null
+++ b/src/sensorcommands.cpp
@@ -0,0 +1,1228 @@
+/*
+// Copyright (c) 2017 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <host-ipmid/ipmid-api.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/container/flat_map.hpp>
+#include <chrono>
+#include <cmath>
+#include <commandutils.hpp>
+#include <iostream>
+#include <phosphor-ipmi-host/utils.hpp>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/bus.hpp>
+#include <sdrutils.hpp>
+#include <sensorcommands.hpp>
+#include <sensorutils.hpp>
+#include <storagecommands.hpp>
+#include <string>
+
+namespace ipmi
+{
+using ManagedObjectType =
+    std::map<sdbusplus::message::object_path,
+             std::map<std::string, std::map<std::string, DbusVariant>>>;
+
+using SensorMap = std::map<std::string, std::map<std::string, DbusVariant>>;
+
+static constexpr int sensorListUpdatePeriod = 10;
+static constexpr int sensorMapUpdatePeriod = 2;
+
+constexpr size_t maxSDRTotalSize =
+    76; // Largest SDR Record Size (type 01) + SDR Overheader Size
+constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
+
+static uint16_t sdrReservationID;
+static uint32_t sdrLastAdd = noTimestamp;
+static uint32_t sdrLastRemove = noTimestamp;
+
+static SensorSubTree sensorTree;
+static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
+
+const static boost::container::flat_map<const char *, SensorUnits> sensorUnits{
+    {{"temperature", SensorUnits::degreesC},
+     {"voltage", SensorUnits::volts},
+     {"current", SensorUnits::amps},
+     {"fan_tach", SensorUnits::rpm},
+     {"power", SensorUnits::watts}}};
+
+void registerSensorFunctions() __attribute__((constructor));
+static sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
+
+static sdbusplus::bus::match::match sensorAdded(
+    dbus,
+    "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
+    "sensors/'",
+    [](sdbusplus::message::message &m) {
+        sensorTree.clear();
+        sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
+                         std::chrono::system_clock::now().time_since_epoch())
+                         .count();
+    });
+
+static sdbusplus::bus::match::match sensorRemoved(
+    dbus,
+    "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
+    "sensors/'",
+    [](sdbusplus::message::message &m) {
+        sensorTree.clear();
+        sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
+                            std::chrono::system_clock::now().time_since_epoch())
+                            .count();
+    });
+
+static void
+    getSensorMaxMin(const std::map<std::string, DbusVariant> &sensorPropertyMap,
+                    double &max, double &min)
+{
+    auto maxMap = sensorPropertyMap.find("MaxValue");
+    auto minMap = sensorPropertyMap.find("MinValue");
+    max = 127;
+    min = -128;
+
+    if (maxMap != sensorPropertyMap.end())
+    {
+        max = apply_visitor(VariantToDoubleVisitor(), maxMap->second);
+    }
+    if (minMap != sensorPropertyMap.end())
+    {
+        min = apply_visitor(VariantToDoubleVisitor(), minMap->second);
+    }
+}
+
+static ipmi_ret_t getSensorConnection(uint8_t sensnum, std::string &connection,
+                                      std::string &path)
+{
+    if (sensorTree.empty() && !getSensorSubtree(sensorTree))
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+
+    if (sensorTree.size() < (sensnum + 1))
+    {
+        return IPMI_CC_INVALID_FIELD_REQUEST;
+    }
+
+    uint8_t sensorIndex = sensnum;
+    for (const auto &sensor : sensorTree)
+    {
+        if (sensorIndex-- == 0)
+        {
+            if (!sensor.second.size())
+            {
+                return IPMI_CC_RESPONSE_ERROR;
+            }
+            connection = sensor.second.begin()->first;
+            path = sensor.first;
+            break;
+        }
+    }
+
+    return 0;
+}
+
+static bool getSensorMap(std::string sensorConnection, std::string sensorPath,
+                         SensorMap &sensorMap)
+{
+    static boost::container::flat_map<
+        std::string, std::chrono::time_point<std::chrono::steady_clock>>
+        updateTimeMap;
+
+    auto updateFind = updateTimeMap.find(sensorConnection);
+    auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
+    if (updateFind != updateTimeMap.end())
+    {
+        lastUpdate = updateFind->second;
+    }
+
+    auto now = std::chrono::steady_clock::now();
+
+    if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
+            .count() > sensorMapUpdatePeriod)
+    {
+        updateTimeMap[sensorConnection] = now;
+
+        auto managedObj = dbus.new_method_call(
+            sensorConnection.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
+            "GetManagedObjects");
+
+        ManagedObjectType managedObjects;
+        try
+        {
+            auto reply = dbus.call(managedObj);
+            reply.read(managedObjects);
+        }
+        catch (sdbusplus::exception_t &)
+        {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "Error getting managed objects from connection",
+                phosphor::logging::entry("CONNECTION=%s",
+                                         sensorConnection.c_str()));
+            return false;
+        }
+
+        SensorCache[sensorConnection] = managedObjects;
+    }
+    auto connection = SensorCache.find(sensorConnection);
+    if (connection == SensorCache.end())
+    {
+        return false;
+    }
+    auto path = connection->second.find(sensorPath);
+    if (path == connection->second.end())
+    {
+        return false;
+    }
+    sensorMap = path->second;
+
+    return true;
+}
+
+/* sensor commands */
+ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+                                     ipmi_request_t request,
+                                     ipmi_response_t response,
+                                     ipmi_data_len_t dataLen,
+                                     ipmi_context_t context)
+{
+    *dataLen = 0;
+    printCommand(+netfn, +cmd);
+    return IPMI_CC_INVALID;
+}
+
+ipmi_ret_t ipmiSenGetSensorReading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+                                   ipmi_request_t request,
+                                   ipmi_response_t response,
+                                   ipmi_data_len_t dataLen,
+                                   ipmi_context_t context)
+{
+    if (*dataLen != 1)
+    {
+        *dataLen = 0;
+        return IPMI_CC_REQ_DATA_LEN_INVALID;
+    }
+    *dataLen = 0; // default to 0 in case of an error
+
+    uint8_t sensnum = *(static_cast<uint8_t *>(request));
+
+    std::string connection;
+    std::string path;
+
+    auto status = getSensorConnection(sensnum, connection, path);
+    if (status)
+    {
+        return status;
+    }
+
+    SensorMap sensorMap;
+    if (!getSensorMap(connection, path, sensorMap))
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+    auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
+
+    if (sensorObject == sensorMap.end() ||
+        sensorObject->second.find("Value") == sensorObject->second.end())
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+    auto &value = sensorObject->second["Value"];
+    double reading = apply_visitor(VariantToDoubleVisitor(), value);
+
+    double max;
+    double min;
+    getSensorMaxMin(sensorObject->second, max, min);
+
+    int16_t mValue = 0;
+    int16_t bValue = 0;
+    int8_t rExp = 0;
+    int8_t bExp = 0;
+    bool bSigned = false;
+
+    if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+
+    SensorReadingResp *msgReply = static_cast<SensorReadingResp *>(response);
+    *dataLen = sizeof(SensorReadingResp);
+
+    msgReply->value =
+        scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
+    msgReply->operation =
+        static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
+    msgReply->indication[0] = 0; // ignore for non-threshold sensors
+    msgReply->indication[1] = 0;
+
+    return IPMI_CC_OK;
+}
+
+ipmi_ret_t ipmiSenSetSensorThresholds(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+                                      ipmi_request_t request,
+                                      ipmi_response_t response,
+                                      ipmi_data_len_t dataLen,
+                                      ipmi_context_t context)
+{
+    if (*dataLen != 8)
+    {
+        *dataLen = 0;
+        return IPMI_CC_REQ_DATA_LEN_INVALID;
+    }
+    *dataLen = 0;
+
+    SensorThresholdReq *req = static_cast<SensorThresholdReq *>(request);
+
+    // upper two bits reserved
+    if (req->mask & 0xC0)
+    {
+        return IPMI_CC_INVALID_FIELD_REQUEST;
+    }
+
+    // lower nc and upper nc not suppported on any sensor
+    if ((req->mask & static_cast<uint8_t>(
+                         SensorThresholdReqEnable::setLowerNonRecoverable)) ||
+        (req->mask & static_cast<uint8_t>(
+                         SensorThresholdReqEnable::setUpperNonRecoverable)))
+    {
+        return IPMI_CC_INVALID_FIELD_REQUEST;
+    }
+
+    // if no bits are set in the mask, nothing to do
+    if (!(req->mask))
+    {
+        return IPMI_CC_OK;
+    }
+
+    std::string connection;
+    std::string path;
+
+    ipmi_ret_t status = getSensorConnection(req->sensorNum, connection, path);
+    if (status)
+    {
+        return status;
+    }
+    SensorMap sensorMap;
+    if (!getSensorMap(connection, path, sensorMap))
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+
+    auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
+
+    if (sensorObject == sensorMap.end())
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+    double max = 0;
+    double min = 0;
+    getSensorMaxMin(sensorObject->second, max, min);
+
+    int16_t mValue = 0;
+    int16_t bValue = 0;
+    int8_t rExp = 0;
+    int8_t bExp = 0;
+    bool bSigned = false;
+
+    if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+
+    bool setLowerCritical =
+        req->mask &
+        static_cast<uint8_t>(SensorThresholdReqEnable::setLowerCritical);
+    bool setUpperCritical =
+        req->mask &
+        static_cast<uint8_t>(SensorThresholdReqEnable::setUpperCritical);
+
+    bool setLowerWarning =
+        req->mask &
+        static_cast<uint8_t>(SensorThresholdReqEnable::setLowerNonCritical);
+    bool setUpperWarning =
+        req->mask &
+        static_cast<uint8_t>(SensorThresholdReqEnable::setUpperNonCritical);
+
+    // store a vector of property name, value to set, and interface
+    std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
+
+    // define the indexes of the tuple
+    constexpr uint8_t propertyName = 0;
+    constexpr uint8_t thresholdValue = 1;
+    constexpr uint8_t interface = 2;
+    // verifiy all needed fields are present
+    if (setLowerCritical || setUpperCritical)
+    {
+        auto findThreshold =
+            sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
+        if (findThreshold == sensorMap.end())
+        {
+            return IPMI_CC_INVALID_FIELD_REQUEST;
+        }
+        if (setLowerCritical)
+        {
+            auto findLower = findThreshold->second.find("CriticalLow");
+            if (findLower == findThreshold->second.end())
+            {
+                return IPMI_CC_INVALID_FIELD_REQUEST;
+            }
+            thresholdsToSet.emplace_back("CriticalLow", req->lowerCritical,
+                                         findThreshold->first);
+        }
+        if (setUpperCritical)
+        {
+            auto findUpper = findThreshold->second.find("CriticalHigh");
+            if (findUpper == findThreshold->second.end())
+            {
+                return IPMI_CC_INVALID_FIELD_REQUEST;
+            }
+            thresholdsToSet.emplace_back("CriticalHigh", req->upperCritical,
+                                         findThreshold->first);
+        }
+    }
+    if (setLowerWarning || setUpperWarning)
+    {
+        auto findThreshold =
+            sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
+        if (findThreshold == sensorMap.end())
+        {
+            return IPMI_CC_INVALID_FIELD_REQUEST;
+        }
+        if (setLowerWarning)
+        {
+            auto findLower = findThreshold->second.find("WarningLow");
+            if (findLower == findThreshold->second.end())
+            {
+                return IPMI_CC_INVALID_FIELD_REQUEST;
+            }
+            thresholdsToSet.emplace_back("WarningLow", req->lowerNonCritical,
+                                         findThreshold->first);
+        }
+        if (setUpperWarning)
+        {
+            auto findUpper = findThreshold->second.find("WarningHigh");
+            if (findUpper == findThreshold->second.end())
+            {
+                return IPMI_CC_INVALID_FIELD_REQUEST;
+            }
+            thresholdsToSet.emplace_back("WarningHigh", req->upperNonCritical,
+                                         findThreshold->first);
+        }
+    }
+
+    for (const auto &property : thresholdsToSet)
+    {
+        // from section 36.3 in the IPMI Spec, assume all linear
+        double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
+                             (bValue * std::pow(10, bExp))) *
+                            std::pow(10, rExp);
+        setDbusProperty(dbus, connection, path, std::get<interface>(property),
+                        std::get<propertyName>(property),
+                        ipmi::Value(valueToSet));
+    }
+
+    return IPMI_CC_OK;
+}
+
+ipmi_ret_t ipmiSenGetSensorThresholds(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+                                      ipmi_request_t request,
+                                      ipmi_response_t response,
+                                      ipmi_data_len_t dataLen,
+                                      ipmi_context_t context)
+{
+    if (*dataLen != 1)
+    {
+        *dataLen = 0;
+        return IPMI_CC_REQ_DATA_LEN_INVALID;
+    }
+    *dataLen = 0; // default to 0 in case of an error
+
+    uint8_t sensnum = *(static_cast<uint8_t *>(request));
+
+    std::string connection;
+    std::string path;
+
+    auto status = getSensorConnection(sensnum, connection, path);
+    if (status)
+    {
+        return status;
+    }
+
+    SensorMap sensorMap;
+    if (!getSensorMap(connection, path, sensorMap))
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+
+    // zero out response buff
+    auto responseClear = static_cast<uint8_t *>(response);
+    std::fill(responseClear, responseClear + sizeof(SensorThresholdResp), 0);
+
+    auto warningInterface =
+        sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
+    auto criticalInterface =
+        sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
+
+    if ((warningInterface != sensorMap.end()) ||
+        (criticalInterface != sensorMap.end()))
+    {
+        auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
+
+        if (sensorPair == sensorMap.end())
+        {
+            // should not have been able to find a sensor not implementing
+            // the sensor object
+            return IPMI_CC_RESPONSE_ERROR;
+        }
+
+        double max;
+        double min;
+        getSensorMaxMin(sensorPair->second, max, min);
+
+        int16_t mValue = 0;
+        int16_t bValue = 0;
+        int8_t rExp = 0;
+        int8_t bExp = 0;
+        bool bSigned = false;
+
+        if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
+        {
+            return IPMI_CC_RESPONSE_ERROR;
+        }
+
+        auto msgReply = static_cast<SensorThresholdResp *>(response);
+
+        if (warningInterface != sensorMap.end())
+        {
+            auto &warningMap = warningInterface->second;
+
+            auto warningHigh = warningMap.find("WarningHigh");
+            auto warningLow = warningMap.find("WarningLow");
+
+            if (warningHigh != warningMap.end())
+            {
+                msgReply->readable |=
+                    1 << static_cast<int>(
+                        IPMIhresholdRespBits::upperNonCritical);
+                double value = apply_visitor(VariantToDoubleVisitor(),
+                                             warningHigh->second);
+                msgReply->uppernc = scaleIPMIValueFromDouble(
+                    value, mValue, rExp, bValue, bExp, bSigned);
+            }
+            if (warningLow != warningMap.end())
+            {
+                msgReply->readable |=
+                    1 << static_cast<int>(
+                        IPMIhresholdRespBits::lowerNonCritical);
+                double value =
+                    apply_visitor(VariantToDoubleVisitor(), warningLow->second);
+                msgReply->lowernc = scaleIPMIValueFromDouble(
+                    value, mValue, rExp, bValue, bExp, bSigned);
+            }
+        }
+        if (criticalInterface != sensorMap.end())
+        {
+            auto &criticalMap = criticalInterface->second;
+
+            auto criticalHigh = criticalMap.find("CriticalHigh");
+            auto criticalLow = criticalMap.find("CriticalLow");
+
+            if (criticalHigh != criticalMap.end())
+            {
+                msgReply->readable |=
+                    1 << static_cast<int>(IPMIhresholdRespBits::upperCritical);
+                double value = apply_visitor(VariantToDoubleVisitor(),
+                                             criticalHigh->second);
+                msgReply->uppercritical = scaleIPMIValueFromDouble(
+                    value, mValue, rExp, bValue, bExp, bSigned);
+            }
+            if (criticalLow != criticalMap.end())
+            {
+                msgReply->readable |=
+                    1 << static_cast<int>(IPMIhresholdRespBits::lowerCritical);
+                double value = apply_visitor(VariantToDoubleVisitor(),
+                                             criticalLow->second);
+                msgReply->lowercritical = scaleIPMIValueFromDouble(
+                    value, mValue, rExp, bValue, bExp, bSigned);
+            }
+        }
+    }
+
+    *dataLen = sizeof(SensorThresholdResp);
+    return IPMI_CC_OK;
+}
+
+ipmi_ret_t ipmiSenGetSensorEventEnable(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+                                       ipmi_request_t request,
+                                       ipmi_response_t response,
+                                       ipmi_data_len_t dataLen,
+                                       ipmi_context_t context)
+{
+    if (*dataLen != 1)
+    {
+        *dataLen = 0;
+        return IPMI_CC_REQ_DATA_LEN_INVALID;
+    }
+    *dataLen = 0; // default to 0 in case of an error
+
+    uint8_t sensnum = *(static_cast<uint8_t *>(request));
+
+    std::string connection;
+    std::string path;
+
+    auto status = getSensorConnection(sensnum, connection, path);
+    if (status)
+    {
+        return status;
+    }
+
+    SensorMap sensorMap;
+    if (!getSensorMap(connection, path, sensorMap))
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+
+    auto warningInterface =
+        sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
+    auto criticalInterface =
+        sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
+
+    if ((warningInterface != sensorMap.end()) ||
+        (criticalInterface != sensorMap.end()))
+    {
+        // zero out response buff
+        auto responseClear = static_cast<uint8_t *>(response);
+        std::fill(responseClear, responseClear + sizeof(SensorEventEnableResp),
+                  0);
+
+        // assume all threshold sensors
+        auto resp = static_cast<SensorEventEnableResp *>(response);
+
+        resp->enabled = static_cast<uint8_t>(
+            IPMISensorEventEnableByte2::sensorScanningEnable);
+        if (warningInterface != sensorMap.end())
+        {
+            auto &warningMap = warningInterface->second;
+
+            auto warningHigh = warningMap.find("WarningHigh");
+            auto warningLow = warningMap.find("WarningLow");
+            if (warningHigh != warningMap.end())
+            {
+                resp->assertionEnabledLSB |= static_cast<uint8_t>(
+                    IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
+                resp->deassertionEnabledLSB |= static_cast<uint8_t>(
+                    IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
+            }
+            if (warningLow != warningMap.end())
+            {
+                resp->assertionEnabledLSB |= static_cast<uint8_t>(
+                    IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
+                resp->deassertionEnabledLSB |= static_cast<uint8_t>(
+                    IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
+            }
+        }
+        if (criticalInterface != sensorMap.end())
+        {
+            auto &criticalMap = criticalInterface->second;
+
+            auto criticalHigh = criticalMap.find("CriticalHigh");
+            auto criticalLow = criticalMap.find("CriticalLow");
+
+            if (criticalHigh != criticalMap.end())
+            {
+                resp->assertionEnabledMSB |= static_cast<uint8_t>(
+                    IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
+                resp->deassertionEnabledMSB |= static_cast<uint8_t>(
+                    IPMISensorEventEnableThresholds::upperCriticalGoingLow);
+            }
+            if (criticalLow != criticalMap.end())
+            {
+                resp->assertionEnabledLSB |= static_cast<uint8_t>(
+                    IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
+                resp->deassertionEnabledLSB |= static_cast<uint8_t>(
+                    IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
+            }
+        }
+        *dataLen =
+            sizeof(SensorEventEnableResp); // todo only return needed bytes
+    }
+    // no thresholds enabled
+    else
+    {
+        *dataLen = 1;
+        auto resp = static_cast<uint8_t *>(response);
+        *resp = static_cast<uint8_t>(
+            IPMISensorEventEnableByte2::eventMessagesEnable);
+        *resp |= static_cast<uint8_t>(
+            IPMISensorEventEnableByte2::sensorScanningEnable);
+    }
+    return IPMI_CC_OK;
+}
+
+ipmi_ret_t ipmiSenGetSensorEventStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+                                       ipmi_request_t request,
+                                       ipmi_response_t response,
+                                       ipmi_data_len_t dataLen,
+                                       ipmi_context_t context)
+{
+    if (*dataLen != 1)
+    {
+        *dataLen = 0;
+        return IPMI_CC_REQ_DATA_LEN_INVALID;
+    }
+    *dataLen = 0; // default to 0 in case of an error
+
+    uint8_t sensnum = *(static_cast<uint8_t *>(request));
+
+    std::string connection;
+    std::string path;
+
+    auto status = getSensorConnection(sensnum, connection, path);
+    if (status)
+    {
+        return status;
+    }
+
+    SensorMap sensorMap;
+    if (!getSensorMap(connection, path, sensorMap))
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+
+    auto warningInterface =
+        sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
+    auto criticalInterface =
+        sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
+
+    // zero out response buff
+    auto responseClear = static_cast<uint8_t *>(response);
+    std::fill(responseClear, responseClear + sizeof(SensorEventStatusResp), 0);
+    auto resp = static_cast<SensorEventStatusResp *>(response);
+    resp->enabled =
+        static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
+
+    if ((warningInterface != sensorMap.end()) ||
+        (criticalInterface != sensorMap.end()))
+    {
+        resp->enabled = static_cast<uint8_t>(
+            IPMISensorEventEnableByte2::eventMessagesEnable);
+        if (warningInterface != sensorMap.end())
+        {
+            auto &warningMap = warningInterface->second;
+
+            auto warningHigh = warningMap.find("WarningAlarmHigh");
+            auto warningLow = warningMap.find("WarningAlarmLow");
+            auto warningHighAlarm = false;
+            auto warningLowAlarm = false;
+
+            if (warningHigh != warningMap.end())
+            {
+                warningHighAlarm = warningHigh->second.get<bool>();
+            }
+            if (warningLow != warningMap.end())
+            {
+                warningLowAlarm = warningLow->second.get<bool>();
+            }
+            if (warningHighAlarm)
+            {
+                resp->assertionsLSB |= static_cast<uint8_t>(
+                    IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
+            }
+            if (warningLowAlarm)
+            {
+                resp->assertionsLSB |= 1; // lower nc going low
+            }
+        }
+        if (criticalInterface != sensorMap.end())
+        {
+            auto &criticalMap = criticalInterface->second;
+
+            auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
+            auto criticalLow = criticalMap.find("CriticalAlarmLow");
+            auto criticalHighAlarm = false;
+            auto criticalLowAlarm = false;
+
+            if (criticalHigh != criticalMap.end())
+            {
+                criticalHighAlarm = criticalHigh->second.get<bool>();
+            }
+            if (criticalLow != criticalMap.end())
+            {
+                criticalLowAlarm = criticalLow->second.get<bool>();
+            }
+            if (criticalHighAlarm)
+            {
+                resp->assertionsMSB |= static_cast<uint8_t>(
+                    IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
+            }
+            if (criticalLowAlarm)
+            {
+                resp->assertionsLSB |= static_cast<uint8_t>(
+                    IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
+            }
+        }
+        *dataLen = sizeof(SensorEventStatusResp);
+    }
+
+    // no thresholds enabled, don't need assertionMSB
+    else
+    {
+        *dataLen = sizeof(SensorEventStatusResp) - 1;
+    }
+
+    return IPMI_CC_OK;
+}
+
+/* end sensor commands */
+
+/* storage commands */
+
+ipmi_ret_t ipmiStorageGetSDRRepositoryInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+                                           ipmi_request_t request,
+                                           ipmi_response_t response,
+                                           ipmi_data_len_t dataLen,
+                                           ipmi_context_t context)
+{
+    printCommand(+netfn, +cmd);
+
+    if (*dataLen)
+    {
+        *dataLen = 0;
+        return IPMI_CC_REQ_DATA_LEN_INVALID;
+    }
+    *dataLen = 0; // default to 0 in case of an error
+
+    if (sensorTree.empty() && !getSensorSubtree(sensorTree))
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+
+    // zero out response buff
+    auto responseClear = static_cast<uint8_t *>(response);
+    std::fill(responseClear, responseClear + sizeof(GetSDRInfoResp), 0);
+
+    auto resp = static_cast<GetSDRInfoResp *>(response);
+    resp->sdrVersion = ipmiSdrVersion;
+    uint16_t recordCount = sensorTree.size();
+
+    // todo: for now, sdr count is number of sensors
+    resp->recordCountLS = recordCount & 0xFF;
+    resp->recordCountMS = recordCount >> 8;
+
+    // free space unspcified
+    resp->freeSpace[0] = 0xFF;
+    resp->freeSpace[1] = 0xFF;
+
+    resp->mostRecentAddition = sdrLastAdd;
+    resp->mostRecentErase = sdrLastRemove;
+    resp->operationSupport = static_cast<uint8_t>(
+        SdrRepositoryInfoOps::overflow); // write not supported
+    resp->operationSupport |=
+        static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
+    resp->operationSupport |= static_cast<uint8_t>(
+        SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
+    *dataLen = sizeof(GetSDRInfoResp);
+    return IPMI_CC_OK;
+}
+
+ipmi_ret_t ipmiStorageGetSDRAllocationInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+                                           ipmi_request_t request,
+                                           ipmi_response_t response,
+                                           ipmi_data_len_t dataLen,
+                                           ipmi_context_t context)
+{
+    if (*dataLen)
+    {
+        *dataLen = 0;
+        return IPMI_CC_REQ_DATA_LEN_INVALID;
+    }
+    *dataLen = 0; // default to 0 in case of an error
+    GetAllocInfoResp *resp = static_cast<GetAllocInfoResp *>(response);
+
+    // 0000h unspecified number of alloc units
+    resp->allocUnitsLSB = 0;
+    resp->allocUnitsMSB = 0;
+
+    // max unit size is size of max record
+    resp->allocUnitSizeLSB = maxSDRTotalSize & 0xFF;
+    resp->allocUnitSizeMSB = maxSDRTotalSize >> 8;
+    // read only sdr, no free alloc blocks
+    resp->allocUnitFreeLSB = 0;
+    resp->allocUnitFreeMSB = 0;
+    resp->allocUnitLargestFreeLSB = 0;
+    resp->allocUnitLargestFreeMSB = 0;
+    // only allow one block at a time
+    resp->maxRecordSize = 1;
+
+    *dataLen = sizeof(GetAllocInfoResp);
+
+    return IPMI_CC_OK;
+}
+
+ipmi_ret_t ipmiStorageReserveSDR(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+                                 ipmi_request_t request,
+                                 ipmi_response_t response,
+                                 ipmi_data_len_t dataLen,
+                                 ipmi_context_t context)
+{
+    printCommand(+netfn, +cmd);
+
+    if (*dataLen)
+    {
+        *dataLen = 0;
+        return IPMI_CC_REQ_DATA_LEN_INVALID;
+    }
+    *dataLen = 0; // default to 0 in case of an error
+    sdrReservationID++;
+    *dataLen = 2;
+    auto resp = static_cast<uint8_t *>(response);
+    resp[0] = sdrReservationID & 0xFF;
+    resp[1] = sdrReservationID >> 8;
+
+    return IPMI_CC_OK;
+}
+
+ipmi_ret_t ipmiStorageGetSDR(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+                             ipmi_request_t request, ipmi_response_t response,
+                             ipmi_data_len_t dataLen, ipmi_context_t context)
+{
+    printCommand(+netfn, +cmd);
+
+    if (*dataLen != 6)
+    {
+        *dataLen = 0;
+        return IPMI_CC_REQ_DATA_LEN_INVALID;
+    }
+    auto requestedSize = *dataLen;
+    *dataLen = 0; // default to 0 in case of an error
+
+    constexpr uint16_t lastRecordIndex = 0xFFFF;
+    auto req = static_cast<GetSDRReq *>(request);
+
+    // reservation required for partial reads with non zero offset into
+    // record
+    if (req->reservationID != sdrReservationID && req->offset)
+    {
+        return IPMI_CC_INVALID_RESERVATION_ID;
+    }
+
+    if (sensorTree.empty() && !getSensorSubtree(sensorTree))
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+
+    size_t fruCount = 0;
+    ipmi_ret_t ret = ipmi::storage::getFruSdrCount(fruCount);
+    if (ret != IPMI_CC_OK)
+    {
+        return ret;
+    }
+
+    size_t lastRecord = sensorTree.size() + fruCount - 1;
+    if (req->recordID == lastRecordIndex)
+    {
+        req->recordID = lastRecord;
+    }
+    if (req->recordID > lastRecord)
+    {
+        return IPMI_CC_INVALID_FIELD_REQUEST;
+    }
+
+    uint16_t nextRecord =
+        lastRecord > (req->recordID + 1) ? req->recordID + 1 : 0XFFFF;
+
+    auto responseClear = static_cast<uint8_t *>(response);
+    std::fill(responseClear, responseClear + requestedSize, 0);
+
+    auto resp = static_cast<get_sdr::GetSdrResp *>(response);
+    resp->next_record_id_lsb = nextRecord & 0xFF;
+    resp->next_record_id_msb = nextRecord >> 8;
+
+    if (req->recordID >= sensorTree.size())
+    {
+        size_t fruIndex = req->recordID - sensorTree.size();
+        if (fruIndex >= fruCount)
+        {
+            return IPMI_CC_INVALID_FIELD_REQUEST;
+        }
+        get_sdr::SensorDataFruRecord data;
+        if (req->offset > sizeof(data))
+        {
+            return IPMI_CC_INVALID_FIELD_REQUEST;
+        }
+        ret = ipmi::storage::getFruSdrs(fruIndex, data);
+        if (ret != IPMI_CC_OK)
+        {
+            return ret;
+        }
+        data.header.record_id_msb = req->recordID << 8;
+        data.header.record_id_lsb = req->recordID & 0xFF;
+        if (sizeof(data) < (req->offset + req->bytesToRead))
+        {
+            req->bytesToRead = sizeof(data) - req->offset;
+        }
+        *dataLen = req->bytesToRead + 2; // next record
+        std::memcpy(&resp->record_data, (char *)&data + req->offset,
+                    req->bytesToRead);
+        return IPMI_CC_OK;
+    }
+
+    std::string connection;
+    std::string path;
+    uint16_t sensorIndex = req->recordID;
+    for (const auto &sensor : sensorTree)
+    {
+        if (sensorIndex-- == 0)
+        {
+            if (!sensor.second.size())
+            {
+                return IPMI_CC_RESPONSE_ERROR;
+            }
+            connection = sensor.second.begin()->first;
+            path = sensor.first;
+            break;
+        }
+    }
+
+    SensorMap sensorMap;
+    if (!getSensorMap(connection, path, sensorMap))
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+    uint8_t sensornumber = (req->recordID & 0xFF);
+    get_sdr::SensorDataFullRecord record = {0};
+
+    record.header.record_id_msb = req->recordID << 8;
+    record.header.record_id_lsb = req->recordID & 0xFF;
+    record.header.sdr_version = ipmiSdrVersion;
+    record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
+    record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
+                                  sizeof(get_sdr::SensorDataRecordHeader);
+    record.key.owner_id = 0x20;
+    record.key.owner_lun = 0x0;
+    record.key.sensor_number = sensornumber;
+
+    record.body.entity_id = 0x0;
+    record.body.entity_instance = 0x01;
+    record.body.sensor_capabilities = 0x60; // auto rearm - todo hysteresis
+    record.body.sensor_type = getSensorTypeFromPath(path);
+    std::string type = getSensorTypeStringFromPath(path);
+    auto typeCstr = type.c_str();
+    auto findUnits = sensorUnits.find(typeCstr);
+    if (findUnits != sensorUnits.end())
+    {
+        record.body.sensor_units_2_base =
+            static_cast<uint8_t>(findUnits->second);
+    } // else default 0x0 unspecified
+
+    record.body.event_reading_type = getSensorEventTypeFromPath(path);
+
+    auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
+    if (sensorObject == sensorMap.end())
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+
+    auto maxObject = sensorObject->second.find("MaxValue");
+    auto minObject = sensorObject->second.find("MinValue");
+    double max = 128;
+    double min = -127;
+    if (maxObject != sensorObject->second.end())
+    {
+        max = apply_visitor(VariantToDoubleVisitor(), maxObject->second);
+    }
+
+    if (minObject != sensorObject->second.end())
+    {
+        min = apply_visitor(VariantToDoubleVisitor(), minObject->second);
+    }
+
+    int16_t mValue;
+    int8_t rExp;
+    int16_t bValue;
+    int8_t bExp;
+    bool bSigned;
+
+    if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+
+    // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
+    record.body.m_lsb = mValue & 0xFF;
+
+    // move the smallest bit of the MSB into place (bit 9)
+    // the MSbs are bits 7:8 in m_msb_and_tolerance
+    uint8_t mMsb = (mValue & (1 << 8)) > 0 ? (1 << 6) : 0;
+
+    // assign the negative
+    if (mValue < 0)
+    {
+        mMsb |= (1 << 7);
+    }
+    record.body.m_msb_and_tolerance = mMsb;
+
+    record.body.b_lsb = bValue & 0xFF;
+
+    // move the smallest bit of the MSB into place
+    // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
+    uint8_t bMsb = (bValue & (1 << 8)) > 0 ? (1 << 6) : 0;
+
+    // assign the negative
+    if (bValue < 0)
+    {
+        bMsb |= (1 << 7);
+    }
+    record.body.b_msb_and_accuracy_lsb = bMsb;
+
+    record.body.r_b_exponents = bExp & 0x7;
+    if (bExp < 0)
+    {
+        record.body.r_b_exponents |= 1 << 3;
+    }
+    record.body.r_b_exponents = (rExp & 0x7) << 4;
+    if (rExp < 0)
+    {
+        record.body.r_b_exponents |= 1 << 7;
+    }
+
+    // todo fill out rest of units
+    if (bSigned)
+    {
+        record.body.sensor_units_1 = 1 << 7;
+    }
+
+    // populate sensor name from path
+    std::string name;
+    size_t nameStart = path.rfind("/");
+    if (nameStart != std::string::npos)
+    {
+        name = path.substr(nameStart + 1, std::string::npos - nameStart);
+    }
+
+    std::replace(name.begin(), name.end(), '_', ' ');
+    if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
+    {
+        name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
+    }
+    record.body.id_string_info = name.size();
+    std::strncpy(record.body.id_string, name.c_str(),
+                 sizeof(record.body.id_string));
+
+    if (sizeof(get_sdr::SensorDataFullRecord) <
+        (req->offset + req->bytesToRead))
+    {
+        req->bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - req->offset;
+    }
+
+    *dataLen =
+        2 + req->bytesToRead; // bytesToRead + MSB and LSB of next record id
+
+    std::memcpy(&resp->record_data, (char *)&record + req->offset,
+                req->bytesToRead);
+
+    return IPMI_CC_OK;
+}
+/* end storage commands */
+
+void registerSensorFunctions()
+{
+    // get firmware version information
+    ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
+                         ipmiSensorWildcardHandler, PRIVILEGE_USER);
+
+    // <Get Sensor Type>
+    ipmiPrintAndRegister(
+        NETFUN_SENSOR,
+        static_cast<ipmi_cmd_t>(IPMINetfnSensorCmds::ipmiCmdGetSensorType),
+        nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
+
+    // <Set Sensor Reading and Event Status>
+    ipmiPrintAndRegister(
+        NETFUN_SENSOR,
+        static_cast<ipmi_cmd_t>(
+            IPMINetfnSensorCmds::ipmiCmdSetSensorReadingAndEventStatus),
+        nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
+
+    // <Get Sensor Reading>
+    ipmiPrintAndRegister(
+        NETFUN_SENSOR,
+        static_cast<ipmi_cmd_t>(IPMINetfnSensorCmds::ipmiCmdGetSensorReading),
+        nullptr, ipmiSenGetSensorReading, PRIVILEGE_USER);
+
+    // <Get Sensor Threshold>
+    ipmiPrintAndRegister(
+        NETFUN_SENSOR,
+        static_cast<ipmi_cmd_t>(IPMINetfnSensorCmds::ipmiCmdGetSensorThreshold),
+        nullptr, ipmiSenGetSensorThresholds, PRIVILEGE_USER);
+
+    ipmiPrintAndRegister(
+        NETFUN_SENSOR,
+        static_cast<ipmi_cmd_t>(IPMINetfnSensorCmds::ipmiCmdSetSensorThreshold),
+        nullptr, ipmiSenSetSensorThresholds, PRIVILEGE_OPERATOR);
+
+    // <Get Sensor Event Enable>
+    ipmiPrintAndRegister(NETFUN_SENSOR,
+                         static_cast<ipmi_cmd_t>(
+                             IPMINetfnSensorCmds::ipmiCmdGetSensorEventEnable),
+                         nullptr, ipmiSenGetSensorEventEnable, PRIVILEGE_USER);
+
+    // <Get Sensor Event Status>
+    ipmiPrintAndRegister(NETFUN_SENSOR,
+                         static_cast<ipmi_cmd_t>(
+                             IPMINetfnSensorCmds::ipmiCmdGetSensorEventStatus),
+                         nullptr, ipmiSenGetSensorEventStatus, PRIVILEGE_USER);
+
+    // register all storage commands for both Sensor and Storage command
+    // versions
+
+    // <Get SDR Repository Info>
+    ipmiPrintAndRegister(
+        NETFUN_STORAGE,
+        static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdGetRepositoryInfo),
+        nullptr, ipmiStorageGetSDRRepositoryInfo, PRIVILEGE_USER);
+
+    // <Get SDR Allocation Info>
+    ipmiPrintAndRegister(NETFUN_STORAGE,
+                         static_cast<ipmi_cmd_t>(
+                             IPMINetfnStorageCmds::ipmiCmdGetSDRAllocationInfo),
+                         nullptr, ipmiStorageGetSDRAllocationInfo,
+                         PRIVILEGE_USER);
+
+    // <Reserve SDR Repo>
+    ipmiPrintAndRegister(NETFUN_SENSOR,
+                         static_cast<ipmi_cmd_t>(
+                             IPMINetfnSensorCmds::ipmiCmdReserveDeviceSDRRepo),
+                         nullptr, ipmiStorageReserveSDR, PRIVILEGE_USER);
+
+    ipmiPrintAndRegister(
+        NETFUN_STORAGE,
+        static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdReserveSDR),
+        nullptr, ipmiStorageReserveSDR, PRIVILEGE_USER);
+
+    // <Get Sdr>
+    ipmiPrintAndRegister(
+        NETFUN_SENSOR,
+        static_cast<ipmi_cmd_t>(IPMINetfnSensorCmds::ipmiCmdGetDeviceSDR),
+        nullptr, ipmiStorageGetSDR, PRIVILEGE_USER);
+
+    ipmiPrintAndRegister(
+        NETFUN_STORAGE,
+        static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdGetSDR), nullptr,
+        ipmiStorageGetSDR, PRIVILEGE_USER);
+    return;
+}
+} // namespace ipmi
diff --git a/src/sensorutils.cpp b/src/sensorutils.cpp
new file mode 100644
index 0000000..62e2cd2
--- /dev/null
+++ b/src/sensorutils.cpp
@@ -0,0 +1,161 @@
+/*
+// Copyright (c) 2017 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <host-ipmid/ipmid-api.h>
+
+#include <cmath>
+#include <iostream>
+#include <phosphor-logging/log.hpp>
+#include <sensorutils.hpp>
+
+namespace ipmi
+{
+static constexpr int16_t maxInt10 = 0x1FF;
+static constexpr int16_t minInt10 = -(0x200);
+static constexpr int8_t maxInt4 = 7;
+static constexpr int8_t minInt4 = -8;
+
+bool getSensorAttributes(const double max, const double min, int16_t &mValue,
+                         int8_t &rExp, int16_t &bValue, int8_t &bExp,
+                         bool &bSigned)
+{
+    // computing y = (10^rRexp) * (Mx + (B*(10^Bexp)))
+    // check for 0, assume always positive
+    double mDouble;
+    double bDouble;
+    if (!(max > min))
+    {
+        phosphor::logging::log<phosphor::logging::level::DEBUG>(
+            "getSensorAttributes: Max must be greater than min");
+        return false;
+    }
+    else
+    {
+        mDouble = (max - min) / 0xFF;
+    }
+    if (!mDouble)
+    {
+        mDouble = 1;
+    }
+
+    if (min < 0)
+    {
+        bSigned = true;
+        bDouble = floor(0.5 + ((max + min) / 2));
+    }
+    else
+    {
+        bSigned = false;
+        bDouble = min;
+    }
+
+    rExp = 0;
+
+    // M too big for 10 bit variable
+    while (mDouble > maxInt10)
+    {
+        if (rExp == maxInt4)
+        {
+            phosphor::logging::log<phosphor::logging::level::DEBUG>(
+                "rExp Too big, Max and Min range too far");
+            return false;
+        }
+        mDouble /= 10;
+        rExp += 1;
+    }
+
+    // M too small, loop until we loose less than 1 eight bit count of precision
+    while (((mDouble - floor(mDouble)) / mDouble) > (1.0 / 255))
+    {
+        if (rExp == minInt4)
+        {
+            phosphor::logging::log<phosphor::logging::level::DEBUG>(
+                "rExp Too Small, Max and Min range too close");
+            return false;
+        }
+        // check to see if we reached the limit of where we can adjust back the
+        // B value
+        if (bDouble / std::pow(10, rExp + minInt4 - 1) > bDouble)
+        {
+            if (mDouble < 1.0)
+            {
+                phosphor::logging::log<phosphor::logging::level::DEBUG>(
+                    "Could not find mValue and B value with enough "
+                    "precision.");
+                return false;
+            }
+            break;
+        }
+        // can't multiply M any more, max precision reached
+        else if (mDouble * 10 > maxInt10)
+        {
+            break;
+        }
+        mDouble *= 10;
+        rExp -= 1;
+    }
+
+    bDouble /= std::pow(10, rExp);
+    bExp = 0;
+
+    // B too big for 10 bit variable
+    while (bDouble > maxInt10 || bDouble < minInt10)
+    {
+        if (bExp == maxInt4)
+        {
+            phosphor::logging::log<phosphor::logging::level::DEBUG>(
+                "bExp Too Big, Max and Min range need to be adjusted");
+            return false;
+        }
+        bDouble /= 10;
+        bExp += 1;
+    }
+
+    while (((fabs(bDouble) - floor(fabs(bDouble))) / fabs(bDouble)) >
+           (1.0 / 255))
+    {
+        if (bExp == minInt4)
+        {
+            phosphor::logging::log<phosphor::logging::level::DEBUG>(
+                "bExp Too Small, Max and Min range need to be adjusted");
+            return false;
+        }
+        bDouble *= 10;
+        bExp -= 1;
+    }
+
+    mValue = static_cast<int16_t>(mDouble + 0.5) & maxInt10;
+    bValue = static_cast<int16_t>(bDouble + 0.5) & maxInt10;
+
+    return true;
+}
+
+uint8_t scaleIPMIValueFromDouble(const double value, const uint16_t mValue,
+                                 const int8_t rExp, const uint16_t bValue,
+                                 const int8_t bExp, const bool bSigned)
+{
+    uint32_t scaledValue =
+        (value - (bValue * std::pow(10, bExp) * std::pow(10, rExp))) /
+        (mValue * std::pow(10, rExp));
+    if (bSigned)
+    {
+        return static_cast<int8_t>(scaledValue);
+    }
+    else
+    {
+        return static_cast<uint8_t>(scaledValue);
+    }
+}
+} // namespace ipmi
\ No newline at end of file
diff --git a/src/storagecommands.cpp b/src/storagecommands.cpp
new file mode 100644
index 0000000..e71d47f
--- /dev/null
+++ b/src/storagecommands.cpp
@@ -0,0 +1,315 @@
+/*
+// Copyright (c) 2017 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <host-ipmid/ipmid-api.h>
+
+#include <boost/container/flat_map.hpp>
+#include <commandutils.hpp>
+#include <iostream>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/message/types.hpp>
+#include <sdbusplus/timer.hpp>
+#include <storagecommands.hpp>
+
+namespace ipmi
+{
+
+namespace storage
+{
+
+constexpr static const size_t maxFruSdrNameSize = 16;
+using ManagedObjectType = boost::container::flat_map<
+    sdbusplus::message::object_path,
+    boost::container::flat_map<
+        std::string, boost::container::flat_map<std::string, DbusVariant>>>;
+using ManagedEntry = std::pair<
+    sdbusplus::message::object_path,
+    boost::container::flat_map<
+        std::string, boost::container::flat_map<std::string, DbusVariant>>>;
+
+constexpr static const char* fruDeviceServiceName = "com.intel.FruDevice";
+
+static std::vector<uint8_t> fruCache;
+static uint8_t cacheBus = 0xFF;
+static uint8_t cacheAddr = 0XFF;
+
+std::unique_ptr<phosphor::Timer> cacheTimer = nullptr;
+
+// we unfortunately have to build a map of hashes in case there is a
+// collision to verify our dev-id
+boost::container::flat_map<uint8_t, std::pair<uint8_t, uint8_t>> deviceHashes;
+
+static sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
+
+bool writeFru()
+{
+    sdbusplus::message::message writeFru = dbus.new_method_call(
+        fruDeviceServiceName, "/xyz/openbmc_project/FruDevice",
+        "xyz.openbmc_project.FruDeviceManager", "WriteFru");
+    writeFru.append(cacheBus, cacheAddr, fruCache);
+    try
+    {
+        sdbusplus::message::message writeFruResp = dbus.call(writeFru);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        // todo: log sel?
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "error writing fru");
+        return false;
+    }
+    return true;
+}
+
+ipmi_ret_t replaceCacheFru(uint8_t devId)
+{
+    static uint8_t lastDevId = 0xFF;
+
+    bool timerRunning = (cacheTimer != nullptr) && !cacheTimer->isExpired();
+    if (lastDevId == devId && timerRunning)
+    {
+        return IPMI_CC_OK; // cache already up to date
+    }
+    // if timer is running, stop it and writeFru manually
+    else if (timerRunning)
+    {
+        cacheTimer->stop();
+        writeFru();
+    }
+
+    sdbusplus::message::message getObjects = dbus.new_method_call(
+        fruDeviceServiceName, "/", "org.freedesktop.DBus.ObjectManager",
+        "GetManagedObjects");
+    ManagedObjectType frus;
+    try
+    {
+        sdbusplus::message::message resp = dbus.call(getObjects);
+        resp.read(frus);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "replaceCacheFru: error getting managed objects");
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+
+    deviceHashes.clear();
+
+    // hash the object paths to create unique device id's. increment on
+    // collision
+    std::hash<std::string> hasher;
+    for (const auto& fru : frus)
+    {
+        auto fruIface = fru.second.find("xyz.openbmc_project.FruDevice");
+        if (fruIface == fru.second.end())
+        {
+            continue;
+        }
+
+        auto busFind = fruIface->second.find("BUS");
+        auto addrFind = fruIface->second.find("ADDRESS");
+        if (busFind == fruIface->second.end() ||
+            addrFind == fruIface->second.end())
+        {
+            phosphor::logging::log<phosphor::logging::level::INFO>(
+                "fru device missing Bus or Address",
+                phosphor::logging::entry("FRU=%s", fru.first.str.c_str()));
+            continue;
+        }
+
+        uint8_t fruBus =
+            sdbusplus::message::variant_ns::get<uint32_t>(busFind->second);
+        uint8_t fruAddr =
+            sdbusplus::message::variant_ns::get<uint32_t>(addrFind->second);
+
+        uint8_t fruHash = 0;
+        if (fruBus != 0 || fruAddr != 0)
+        {
+            fruHash = hasher(fru.first.str);
+            // can't be 0xFF based on spec, and 0 is reserved for baseboard
+            if (fruHash == 0 || fruHash == 0xFF)
+            {
+                fruHash = 1;
+            }
+        }
+        std::pair<uint8_t, uint8_t> newDev(fruBus, fruAddr);
+
+        bool emplacePassed = false;
+        while (!emplacePassed)
+        {
+            auto resp = deviceHashes.emplace(fruHash, newDev);
+            emplacePassed = resp.second;
+            if (!emplacePassed)
+            {
+                fruHash++;
+                // can't be 0xFF based on spec, and 0 is reserved for
+                // baseboard
+                if (fruHash == 0XFF)
+                {
+                    fruHash = 0x1;
+                }
+            }
+        }
+    }
+    auto deviceFind = deviceHashes.find(devId);
+    if (deviceFind == deviceHashes.end())
+    {
+        return IPMI_CC_SENSOR_INVALID;
+    }
+
+    fruCache.clear();
+    sdbusplus::message::message getRawFru = dbus.new_method_call(
+        fruDeviceServiceName, "/xyz/openbmc_project/FruDevice",
+        "xyz.openbmc_project.FruDeviceManager", "GetRawFru");
+    cacheBus = deviceFind->second.first;
+    cacheAddr = deviceFind->second.second;
+    getRawFru.append(cacheBus, cacheAddr);
+    try
+    {
+        sdbusplus::message::message getRawResp = dbus.call(getRawFru);
+        getRawResp.read(fruCache);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        lastDevId = 0xFF;
+        cacheBus = 0xFF;
+        cacheAddr = 0xFF;
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+
+    lastDevId = devId;
+    return IPMI_CC_OK;
+}
+
+ipmi_ret_t getFruSdrCount(size_t& count)
+{
+    ipmi_ret_t ret = replaceCacheFru(0);
+    if (ret != IPMI_CC_OK)
+    {
+        return ret;
+    }
+    count = deviceHashes.size();
+    return IPMI_CC_OK;
+}
+
+ipmi_ret_t getFruSdrs(size_t index, get_sdr::SensorDataFruRecord& resp)
+{
+    ipmi_ret_t ret = replaceCacheFru(0); // this will update the hash list
+    if (ret != IPMI_CC_OK)
+    {
+        return ret;
+    }
+    if (deviceHashes.size() < index)
+    {
+        return IPMI_CC_INVALID_FIELD_REQUEST;
+    }
+    auto device = deviceHashes.begin() + index;
+    uint8_t& bus = device->second.first;
+    uint8_t& address = device->second.second;
+
+    ManagedObjectType frus;
+
+    sdbusplus::message::message getObjects = dbus.new_method_call(
+        fruDeviceServiceName, "/", "org.freedesktop.DBus.ObjectManager",
+        "GetManagedObjects");
+    try
+    {
+        sdbusplus::message::message resp = dbus.call(getObjects);
+        resp.read(frus);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+    boost::container::flat_map<std::string, DbusVariant>* fruData = nullptr;
+    auto fru =
+        std::find_if(frus.begin(), frus.end(),
+                     [bus, address, &fruData](ManagedEntry& entry) {
+                         auto findFruDevice =
+                             entry.second.find("xyz.openbmc_project.FruDevice");
+                         if (findFruDevice == entry.second.end())
+                         {
+                             return false;
+                         }
+                         fruData = &(findFruDevice->second);
+                         auto findBus = findFruDevice->second.find("BUS");
+                         auto findAddress =
+                             findFruDevice->second.find("ADDRESS");
+                         if (findBus == findFruDevice->second.end() ||
+                             findAddress == findFruDevice->second.end())
+                         {
+                             return false;
+                         }
+                         if (sdbusplus::message::variant_ns::get<uint32_t>(
+                                 findBus->second) != bus)
+                         {
+                             return false;
+                         }
+                         if (sdbusplus::message::variant_ns::get<uint32_t>(
+                                 findAddress->second) != address)
+                         {
+                             return false;
+                         }
+                         return true;
+                     });
+    if (fru == frus.end())
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+    std::string name;
+    auto findProductName = fruData->find("BOARD_PRODUCT_NAME");
+    auto findBoardName = fruData->find("PRODUCT_PRODUCT_NAME");
+    if (findProductName != fruData->end())
+    {
+        name = sdbusplus::message::variant_ns::get<std::string>(
+            findProductName->second);
+    }
+    else if (findBoardName != fruData->end())
+    {
+        name = sdbusplus::message::variant_ns::get<std::string>(
+            findBoardName->second);
+    }
+    else
+    {
+        name = "UNKNOWN";
+    }
+    if (name.size() > maxFruSdrNameSize)
+    {
+        name = name.substr(0, maxFruSdrNameSize);
+    }
+    size_t sizeDiff = maxFruSdrNameSize - name.size();
+
+    resp.header.record_id_lsb = 0x0; // calling code is to implement these
+    resp.header.record_id_msb = 0x0;
+    resp.header.sdr_version = ipmiSdrVersion;
+    resp.header.record_type = 0x11; // FRU Device Locator
+    resp.header.record_length = sizeof(resp.body) + sizeof(resp.key) - sizeDiff;
+    resp.key.deviceAddress = 0x20;
+    resp.key.fruID = device->first;
+    resp.key.accessLun = 0x80; // logical / physical fru device
+    resp.key.channelNumber = 0x0;
+    resp.body.reserved = 0x0;
+    resp.body.deviceType = 0x10;
+    resp.body.entityID = 0x0;
+    resp.body.entityInstance = 0x1;
+    resp.body.oem = 0x0;
+    resp.body.deviceIDLen = name.size();
+    name.copy(resp.body.deviceID, name.size());
+
+    return IPMI_CC_OK;
+}
+} // namespace storage
+} // namespace ipmi
\ No newline at end of file
diff --git a/src/utils.cpp b/src/utils.cpp
new file mode 100644
index 0000000..3851e82
--- /dev/null
+++ b/src/utils.cpp
@@ -0,0 +1,567 @@
+#include "phosphor-ipmi-host/utils.hpp"
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <net/if.h>
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
+
+namespace ipmi
+{
+
+using namespace phosphor::logging;
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+
+namespace network
+{
+
+/** @brief checks if the given ip is Link Local Ip or not.
+ *  @param[in] ipaddress - IPAddress.
+ */
+bool isLinkLocalIP(const std::string& ipaddress);
+
+} // namespace network
+
+// TODO There may be cases where an interface is implemented by multiple
+//  objects,to handle such cases we are interested on that object
+//  which are on interested busname.
+//  Currently mapper doesn't give the readable busname(gives busid) so we can't
+//  use busname to find the object,will do later once the support is there.
+
+DbusObjectInfo getDbusObject(sdbusplus::bus::bus& bus,
+                             const std::string& interface,
+                             const std::string& serviceRoot,
+                             const std::string& match)
+{
+    std::vector<DbusInterface> interfaces;
+    interfaces.emplace_back(interface);
+
+    auto depth = 0;
+
+    auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ,
+                                          MAPPER_INTF, "GetSubTree");
+
+    mapperCall.append(serviceRoot, depth, interfaces);
+
+    ObjectTree objectTree;
+    try
+    {
+        auto mapperReply = bus.call(mapperCall);
+        mapperReply.read(objectTree);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        log<level::ERR>("Error in mapper call");
+        elog<InternalFailure>();
+    }
+
+    if (objectTree.empty())
+    {
+        log<level::ERR>("No Object has implemented the interface",
+                        entry("INTERFACE=%s", interface.c_str()));
+        elog<InternalFailure>();
+    }
+
+    DbusObjectInfo objectInfo;
+
+    // if match is empty then return the first object
+    if (match == "")
+    {
+        objectInfo = std::make_pair(
+            objectTree.begin()->first,
+            std::move(objectTree.begin()->second.begin()->first));
+        return objectInfo;
+    }
+
+    // else search the match string in the object path
+    auto objectFound = false;
+    for (auto& object : objectTree)
+    {
+        if (object.first.find(match) != std::string::npos)
+        {
+            objectFound = true;
+            objectInfo = make_pair(object.first,
+                                   std::move(object.second.begin()->first));
+            break;
+        }
+    }
+
+    if (!objectFound)
+    {
+        log<level::ERR>("Failed to find object which matches",
+                        entry("MATCH=%s", match.c_str()));
+        elog<InternalFailure>();
+    }
+    return objectInfo;
+}
+
+DbusObjectInfo getIPObject(sdbusplus::bus::bus& bus,
+                           const std::string& interface,
+                           const std::string& serviceRoot,
+                           const std::string& match)
+{
+    auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, match);
+
+    if (objectTree.empty())
+    {
+        log<level::ERR>("No Object has implemented the IP interface",
+                        entry("INTERFACE=%s", interface.c_str()));
+        elog<InternalFailure>();
+    }
+
+    DbusObjectInfo objectInfo;
+
+    for (auto& object : objectTree)
+    {
+        auto variant = ipmi::getDbusProperty(
+            bus, object.second.begin()->first, object.first,
+            ipmi::network::IP_INTERFACE, "Address");
+
+        objectInfo = std::make_pair(object.first, object.second.begin()->first);
+
+        // if LinkLocalIP found look for Non-LinkLocalIP
+        if (ipmi::network::isLinkLocalIP(variant.get<std::string>()))
+        {
+            continue;
+        }
+        else
+        {
+            break;
+        }
+    }
+    return objectInfo;
+}
+
+Value getDbusProperty(sdbusplus::bus::bus& bus, const std::string& service,
+                      const std::string& objPath, const std::string& interface,
+                      const std::string& property)
+{
+
+    Value value;
+
+    auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
+                                      PROP_INTF, METHOD_GET);
+
+    method.append(interface, property);
+
+    try
+    {
+        auto reply = bus.call(method);
+        reply.read(value);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        log<level::ERR>("Failed to get property",
+                        entry("PROPERTY=%s", property.c_str()),
+                        entry("PATH=%s", objPath.c_str()),
+                        entry("INTERFACE=%s", interface.c_str()));
+        elog<InternalFailure>();
+    }
+
+    return value;
+}
+
+PropertyMap getAllDbusProperties(sdbusplus::bus::bus& bus,
+                                 const std::string& service,
+                                 const std::string& objPath,
+                                 const std::string& interface)
+{
+    PropertyMap properties;
+
+    auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
+                                      PROP_INTF, METHOD_GET_ALL);
+
+    method.append(interface);
+
+    try
+    {
+        auto reply = bus.call(method);
+        reply.read(properties);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        log<level::ERR>("Failed to get all properties",
+                        entry("PATH=%s", objPath.c_str()),
+                        entry("INTERFACE=%s", interface.c_str()));
+        elog<InternalFailure>();
+    }
+
+    return properties;
+}
+
+ObjectValueTree getManagedObjects(sdbusplus::bus::bus& bus,
+                                  const std::string& service,
+                                  const std::string& objPath)
+{
+    ipmi::ObjectValueTree interfaces;
+
+    auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
+                                      "org.freedesktop.DBus.ObjectManager",
+                                      "GetManagedObjects");
+
+    try
+    {
+        auto reply = bus.call(method);
+        reply.read(interfaces);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        log<level::ERR>("Failed to get managed objects",
+                        entry("PATH=%s", objPath.c_str()));
+        elog<InternalFailure>();
+    }
+
+    return interfaces;
+}
+
+void setDbusProperty(sdbusplus::bus::bus& bus, const std::string& service,
+                     const std::string& objPath, const std::string& interface,
+                     const std::string& property, const Value& value)
+{
+    auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
+                                      PROP_INTF, METHOD_SET);
+
+    method.append(interface, property, value);
+
+    try
+    {
+        bus.call(method);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        log<level::ERR>("Failed to set property",
+                        entry("PROPERTY=%s", property.c_str()),
+                        entry("PATH=%s", objPath.c_str()),
+                        entry("INTERFACE=%s", interface.c_str()));
+        elog<InternalFailure>();
+    }
+}
+
+ServiceCache::ServiceCache(const std::string& intf, const std::string& path) :
+    intf(intf), path(path), cachedService(std::experimental::nullopt),
+    cachedBusName(std::experimental::nullopt)
+{
+}
+
+ServiceCache::ServiceCache(std::string&& intf, std::string&& path) :
+    intf(std::move(intf)), path(std::move(path)),
+    cachedService(std::experimental::nullopt),
+    cachedBusName(std::experimental::nullopt)
+{
+}
+
+const std::string& ServiceCache::getService(sdbusplus::bus::bus& bus)
+{
+    if (!isValid(bus))
+    {
+        cachedBusName = bus.get_unique_name();
+        cachedService = ::ipmi::getService(bus, intf, path);
+    }
+    return cachedService.value();
+}
+
+void ServiceCache::invalidate()
+{
+    cachedBusName = std::experimental::nullopt;
+    cachedService = std::experimental::nullopt;
+}
+
+sdbusplus::message::message
+    ServiceCache::newMethodCall(sdbusplus::bus::bus& bus, const char* intf,
+                                const char* method)
+{
+    return bus.new_method_call(getService(bus).c_str(), path.c_str(), intf,
+                               method);
+}
+
+bool ServiceCache::isValid(sdbusplus::bus::bus& bus) const
+{
+    return cachedService && cachedBusName == bus.get_unique_name();
+}
+
+std::string getService(sdbusplus::bus::bus& bus, const std::string& intf,
+                       const std::string& path)
+{
+    auto mapperCall =
+        bus.new_method_call("xyz.openbmc_project.ObjectMapper",
+                            "/xyz/openbmc_project/object_mapper",
+                            "xyz.openbmc_project.ObjectMapper", "GetObject");
+
+    mapperCall.append(path);
+    mapperCall.append(std::vector<std::string>({intf}));
+
+    std::map<std::string, std::vector<std::string>> mapperResponse;
+    try
+    {
+        auto mapperResponseMsg = bus.call(mapperCall);
+        mapperResponseMsg.read(mapperResponse);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        throw std::runtime_error("ERROR in mapper call");
+    }
+
+    if (mapperResponse.begin() == mapperResponse.end())
+    {
+        throw std::runtime_error("ERROR in reading the mapper response");
+    }
+
+    return mapperResponse.begin()->first;
+}
+
+ipmi::ObjectTree getAllDbusObjects(sdbusplus::bus::bus& bus,
+                                   const std::string& serviceRoot,
+                                   const std::string& interface,
+                                   const std::string& match)
+{
+    std::vector<std::string> interfaces;
+    interfaces.emplace_back(interface);
+
+    auto depth = 0;
+
+    auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ,
+                                          MAPPER_INTF, "GetSubTree");
+
+    mapperCall.append(serviceRoot, depth, interfaces);
+
+    ObjectTree objectTree;
+    try
+    {
+        auto mapperReply = bus.call(mapperCall);
+        mapperReply.read(objectTree);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        log<level::ERR>("Error in mapper call",
+                        entry("SERVICEROOT=%s", serviceRoot.c_str()),
+                        entry("INTERFACE=%s", interface.c_str()));
+
+        elog<InternalFailure>();
+    }
+
+    for (auto it = objectTree.begin(); it != objectTree.end();)
+    {
+        if (it->first.find(match) == std::string::npos)
+        {
+            it = objectTree.erase(it);
+        }
+        else
+        {
+            ++it;
+        }
+    }
+
+    return objectTree;
+}
+
+void deleteAllDbusObjects(sdbusplus::bus::bus& bus,
+                          const std::string& serviceRoot,
+                          const std::string& interface,
+                          const std::string& match)
+{
+    try
+    {
+        auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, match);
+
+        for (auto& object : objectTree)
+        {
+            method_no_args::callDbusMethod(bus, object.second.begin()->first,
+                                           object.first, DELETE_INTERFACE,
+                                           "Delete");
+        }
+    }
+    catch (sdbusplus::exception::exception& e)
+    {
+        log<level::INFO>("sdbusplus exception - Unable to delete the objects",
+                         entry("ERROR=%s", e.what()),
+                         entry("INTERFACE=%s", interface.c_str()),
+                         entry("SERVICE=%s", serviceRoot.c_str()));
+    }
+}
+
+ObjectTree getAllAncestors(sdbusplus::bus::bus& bus, const std::string& path,
+                           InterfaceList&& interfaces)
+{
+    auto convertToString = [](InterfaceList& interfaces) -> std::string {
+        std::string intfStr;
+        for (const auto& intf : interfaces)
+        {
+            intfStr += "," + intf;
+        }
+        return intfStr;
+    };
+
+    auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ,
+                                          MAPPER_INTF, "GetAncestors");
+    mapperCall.append(path, interfaces);
+
+    ObjectTree objectTree;
+    try
+    {
+        auto mapperReply = bus.call(mapperCall);
+        mapperReply.read(objectTree);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        log<level::ERR>(
+            "Error in mapper call", entry("PATH=%s", path.c_str()),
+            entry("INTERFACES=%s", convertToString(interfaces).c_str()));
+
+        elog<InternalFailure>();
+    }
+
+    if (objectTree.empty())
+    {
+        log<level::ERR>(
+            "No Object has implemented the interface",
+            entry("PATH=%s", path.c_str()),
+            entry("INTERFACES=%s", convertToString(interfaces).c_str()));
+        elog<InternalFailure>();
+    }
+
+    return objectTree;
+}
+
+namespace method_no_args
+{
+
+void callDbusMethod(sdbusplus::bus::bus& bus, const std::string& service,
+                    const std::string& objPath, const std::string& interface,
+                    const std::string& method)
+
+{
+    auto busMethod = bus.new_method_call(service.c_str(), objPath.c_str(),
+                                         interface.c_str(), method.c_str());
+
+    try
+    {
+        bus.call(busMethod);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        log<level::ERR>("Failed to execute method",
+                        entry("METHOD=%s", method.c_str()),
+                        entry("PATH=%s", objPath.c_str()),
+                        entry("INTERFACE=%s", interface.c_str()));
+        elog<InternalFailure>();
+    }
+}
+
+} // namespace method_no_args
+
+namespace network
+{
+
+bool isLinkLocalIP(const std::string& address)
+{
+    return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
+}
+
+void createIP(sdbusplus::bus::bus& bus, const std::string& service,
+              const std::string& objPath, const std::string& protocolType,
+              const std::string& ipaddress, uint8_t prefix)
+{
+    std::string gateway = "";
+
+    auto busMethod = bus.new_method_call(service.c_str(), objPath.c_str(),
+                                         IP_CREATE_INTERFACE, "IP");
+
+    busMethod.append(protocolType, ipaddress, prefix, gateway);
+
+    try
+    {
+        bus.call(busMethod);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        log<level::ERR>("Failed to execute method", entry("METHOD=%s", "IP"),
+                        entry("PATH=%s", objPath.c_str()));
+        elog<InternalFailure>();
+    }
+}
+
+void createVLAN(sdbusplus::bus::bus& bus, const std::string& service,
+                const std::string& objPath, const std::string& interfaceName,
+                uint32_t vlanID)
+{
+    auto busMethod = bus.new_method_call(service.c_str(), objPath.c_str(),
+                                         VLAN_CREATE_INTERFACE, "VLAN");
+
+    busMethod.append(interfaceName, vlanID);
+
+    try
+    {
+        bus.call(busMethod);
+    }
+    catch (sdbusplus::exception_t&)
+    {
+        log<level::ERR>("Failed to execute method", entry("METHOD=%s", "VLAN"),
+                        entry("PATH=%s", objPath.c_str()));
+        elog<InternalFailure>();
+    }
+}
+
+uint8_t toPrefix(int addressFamily, const std::string& subnetMask)
+{
+    if (addressFamily == AF_INET6)
+    {
+        return 0;
+    }
+
+    uint32_t buff{};
+
+    auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
+    if (rc <= 0)
+    {
+        log<level::ERR>("inet_pton failed:",
+                        entry("SUBNETMASK=%s", subnetMask.c_str()));
+        return 0;
+    }
+
+    buff = be32toh(buff);
+    // total no of bits - total no of leading zero == total no of ones
+    if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) ==
+        __builtin_popcount(buff))
+    {
+        return __builtin_popcount(buff);
+    }
+    else
+    {
+        log<level::ERR>("Invalid Mask",
+                        entry("SUBNETMASK=%s", subnetMask.c_str()));
+        return 0;
+    }
+}
+
+uint32_t getVLAN(const std::string& path)
+{
+    // Path would be look like
+    // /xyz/openbmc_project/network/eth0_443/ipv4
+
+    uint32_t vlanID = 0;
+    try
+    {
+        auto intfObjectPath = path.substr(0, path.find(IP_TYPE) - 1);
+
+        auto intfName = intfObjectPath.substr(intfObjectPath.rfind("/") + 1);
+
+        auto index = intfName.find("_");
+        if (index != std::string::npos)
+        {
+            auto str = intfName.substr(index + 1);
+            vlanID = std::stoul(str);
+        }
+    }
+    catch (std::exception& e)
+    {
+        log<level::ERR>("Exception occurred during getVLAN",
+                        entry("PATH=%s", path.c_str()),
+                        entry("EXCEPTION=%s", e.what()));
+    }
+    return vlanID;
+}
+
+} // namespace network
+} // namespace ipmi