ipmbbridge initial implementation

ipmbbridge gives the ability for openbmc to host ipmb transactions over
smbus

Change-Id: I3744dbef5a6db0b2ff4f2b691e68ca8dc3b1d24b
Signed-off-by: Dawid Frycki <dawid.frycki@intel.com>
Signed-off-by: Ed Tanous <ed.tanous@intel.com>
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..dd27708
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,98 @@
+---
+Language:        Cpp
+# BasedOnStyle:  LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands:   true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: false
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+  AfterClass:      true
+  AfterControlStatement: true
+  AfterEnum:       true
+  AfterFunction:   true
+  AfterNamespace:  true
+  AfterObjCDeclaration: true
+  AfterStruct:     true
+  AfterUnion:      true
+  BeforeCatch:     true
+  BeforeElse:      true
+  IndentBraces:    false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: AfterColon
+ColumnLimit:     80
+CommentPragmas:  '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: true
+PointerAlignment: Left
+DisableFormat:   false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeBlocks: Regroup
+IncludeCategories:
+  - Regex:           '^[<"](gtest|gmock)'
+    Priority:        5
+  - Regex:           '^"config.h"'
+    Priority:        -1
+  - Regex:           '^".*\.hpp"'
+    Priority:        1
+  - Regex:           '^<.*\.h>'
+    Priority:        2
+  - Regex:           '^<.*'
+    Priority:        3
+  - Regex:           '.*'
+    Priority:        4
+IndentCaseLabels: true
+IndentWidth:     4
+IndentWrappedFunctionNames: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd:   ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Right
+ReflowComments:  true
+SortIncludes:    true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles:  false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard:        Cpp11
+TabWidth:        4
+UseTab:          Never
+...
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..d9e8d1b
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,66 @@
+cmake_minimum_required (VERSION 3.5 FATAL_ERROR)
+project (ipmbbridged CXX)
+set (CMAKE_CXX_STANDARD 17)
+set (CMAKE_CXX_STANDARD_REQUIRED ON)
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
+set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti")
+
+# check for necessary headers / download if missing
+enable_language (C)
+include (CheckIncludeFile)
+check_include_file ("linux/i2c-dev-user.h" header_present)
+if (NOT header_present)
+    message (
+        "Could not find linux/i2c-dev-user.h: Attempting to download locally "
+        "for building from https://raw.githubusercontent.com/openbmc/linux/"
+        "dev-4.13/include/uapi/linux/i2c-dev.h"
+    )
+
+    string (CONCAT url "https://raw.githubusercontent.com/openbmc/linux/"
+                   "dev-4.13/include/uapi/linux/i2c-dev.h")
+
+    file (DOWNLOAD ${url} "linux/i2c-dev-user.h" SHOW_PROGRESS STATUS status)
+
+    list (GET status 0 status_code)
+
+    if (NOT status_code EQUAL 0)
+        message (FATAL_ERROR "i2c-dev-user.h missing")
+    endif ()
+endif ()
+
+include_directories (${CMAKE_CURRENT_SOURCE_DIR})
+find_package (Boost REQUIRED)
+include_directories (${Boost_INCLUDE_DIRS})
+add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY)
+add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED)
+add_definitions (-DBOOST_ALL_NO_LIB)
+add_definitions (-DBOOST_NO_RTTI)
+add_definitions (-DBOOST_NO_TYPEID)
+add_definitions (-DBOOST_ASIO_DISABLE_THREADS)
+
+set (SRC_FILES ipmbbridged.cpp ipmbutils.cpp)
+
+# import libsystemd
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (SYSTEMD libsystemd REQUIRED)
+
+# import sdbusplus
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED)
+
+# import phosphor-logging
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (LOGGING phosphor-logging REQUIRED)
+
+add_executable (${PROJECT_NAME} ${SRC_FILES})
+target_link_libraries (${PROJECT_NAME} systemd)
+target_link_libraries (${PROJECT_NAME} boost_coroutine)
+target_link_libraries (${PROJECT_NAME} sdbusplus -lstdc++fs)
+target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES})
+
+link_directories (${EXTERNAL_INSTALL_LOCATION}/lib)
+
+set (SERVICE_FILES ${PROJECT_SOURCE_DIR}/ipmb.service)
+
+install (TARGETS ${PROJECT_NAME} DESTINATION sbin)
+install (FILES ${SERVICE_FILES} DESTINATION /lib/systemd/system/)
diff --git a/LICENSE b/LICENSE
index 261eeb9..8dada3e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -178,7 +178,7 @@
    APPENDIX: How to apply the Apache License to your work.
 
       To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
+      boilerplate notice, with the fields enclosed by brackets "{}"
       replaced with your own identifying information. (Don't include
       the brackets!)  The text should be enclosed in the appropriate
       comment syntax for the file format. We also recommend that a
@@ -186,7 +186,7 @@
       same "printed page" as the copyright notice for easier
       identification within third-party archives.
 
-   Copyright [yyyy] [name of copyright owner]
+   Copyright {yyyy} {name of copyright owner}
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
diff --git a/README.md b/README.md
deleted file mode 100644
index 8179931..0000000
--- a/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# ipmbbridge
\ No newline at end of file
diff --git a/cmake-format.json b/cmake-format.json
new file mode 100644
index 0000000..2463dc1
--- /dev/null
+++ b/cmake-format.json
@@ -0,0 +1,12 @@
+{

+  "enum_char": ".",

+  "line_ending": "unix",

+  "bullet_char": "*",

+  "max_subargs_per_line": 99,

+  "command_case": "lower",

+  "tab_size": 4,

+  "line_width": 80,

+  "separate_fn_name_with_space": true,

+  "dangle_parens": true,

+  "separate_ctrl_name_with_space": true

+}
\ No newline at end of file
diff --git a/ipmb.service b/ipmb.service
new file mode 100644
index 0000000..a940e1e
--- /dev/null
+++ b/ipmb.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=IPMB bridge
+After=phosphor-ipmi-host.service
+
+[Service]
+ExecStart=/usr/sbin/ipmbbridged
+SyslogIdentifier=ipmbbridged
+Restart=always
+Type=simple
+
+[Install]
+WantedBy=basic.target
\ No newline at end of file
diff --git a/ipmbbridged.cpp b/ipmbbridged.cpp
new file mode 100644
index 0000000..2f78cd0
--- /dev/null
+++ b/ipmbbridged.cpp
@@ -0,0 +1,752 @@
+/* Copyright 2018 Intel
+ *
+ * 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 "ipmbbridged.hpp"
+
+#include "ipmbdefines.hpp"
+#include "ipmbutils.hpp"
+
+#include <linux/i2c-dev-user.h>
+
+#include <phosphor-logging/log.hpp>
+#include <tuple>
+
+/**
+ * @brief Dbus
+ */
+static constexpr const char *ipmbBus = "xyz.openbmc_project.Ipmi.Channel.Ipmb";
+static constexpr const char *ipmbObj = "/xyz/openbmc_project/Ipmi/Channel/Ipmb";
+static constexpr const char *hostIpmiIntf = "org.openbmc.HostIpmi";
+static constexpr const char *ipmbDbusIntf = "org.openbmc.Ipmb";
+
+boost::asio::io_service io;
+auto conn = std::make_shared<sdbusplus::asio::connection>(io);
+
+/**
+ * @brief Channel configuration table
+ * TODO : move to user configuration as JSON file
+ */
+static const std::vector<IpmbChannelConfig> ipmbChannelsConfig = {
+    // ME channel
+    {ipmbChannelType::me, "/sys/bus/i2c/devices/5-1010/slave-mqueue",
+     "/dev/i2c-5", 0x20, 0x2C}, // 8 bit addresses
+    // IPMB header channel
+    {ipmbChannelType::ipmb, "/sys/bus/i2c/devices/0-1010/slave-mqueue",
+     "/dev/i2c-0", 0x20, 0x58}}; // 8 bit addresses
+
+static std::list<IpmbChannel> ipmbChannels;
+
+/**
+ * @brief Ipmb request class methods
+ */
+IpmbRequest::IpmbRequest()
+{
+    data.reserve(ipmbMaxDataSize);
+}
+
+IpmbRequest::IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun,
+                         uint8_t rqSA, uint8_t seq, uint8_t rqLun, uint8_t cmd,
+                         std::vector<uint8_t> &inputData) :
+    address(address),
+    netFn(netFn), rsLun(rsLun), rqSA(rqSA), seq(seq), rqLun(rqLun), cmd(cmd),
+    timer(io)
+{
+    data.reserve(ipmbMaxDataSize);
+    state = ipmbRequestState::invalid;
+
+    if (inputData.size() > 0)
+    {
+        data = std::move(inputData);
+    }
+}
+
+void IpmbRequest::incomingMessageHandler()
+{
+    sdbusplus::message::message mesg =
+        conn->new_signal(ipmbObj, hostIpmiIntf, "ReceivedMessage");
+    mesg.append(seq, netFn, rsLun, cmd, data);
+    mesg.signal_send();
+}
+
+void IpmbRequest::i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer,
+                                     size_t bufferLength)
+{
+    // constructing ipmb request from i2c buffer
+    netFn = ipmbNetFnGet(ipmbBuffer->Header.Req.rsNetFnLUN);
+    rsLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Req.rsNetFnLUN);
+    rqSA = ipmbBuffer->Header.Req.rqSA;
+    seq = ipmbSeqGet(ipmbBuffer->Header.Req.rqSeqLUN);
+    rqLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Req.rqSeqLUN);
+    cmd = ipmbBuffer->Header.Req.cmd;
+
+    size_t dataLength =
+        bufferLength - (ipmbConnectionHeaderLength +
+                        ipmbRequestDataHeaderLength + ipmbChecksumSize);
+
+    if (dataLength > 0)
+    {
+        data.insert(data.end(), ipmbBuffer->Header.Req.data,
+                    &ipmbBuffer->Header.Req.data[dataLength]);
+    }
+}
+
+int IpmbRequest::ipmbToi2cConstruct(std::vector<uint8_t> &buffer)
+{
+    size_t bufferLength = data.size() + ipmbRequestDataHeaderLength +
+                          ipmbConnectionHeaderLength + ipmbChecksumSize;
+
+    if (bufferLength > ipmbMaxFrameLength)
+    {
+        return -1;
+    }
+
+    buffer.resize(bufferLength);
+    static_assert(ipmbMaxFrameLength >= sizeof(IPMB_HEADER));
+    auto ipmbBuffer = reinterpret_cast<IPMB_HEADER *>(buffer.data());
+
+    // constructing buffer from ipmb request
+    ipmbBuffer->Header.Req.address = address;
+    ipmbBuffer->Header.Req.rsNetFnLUN = ipmbNetFnLunSet(netFn, rsLun);
+    ipmbBuffer->Header.Req.rqSA = rqSA;
+    ipmbBuffer->Header.Req.rqSeqLUN = ipmbSeqLunSet(seq, rqLun);
+    ipmbBuffer->Header.Req.cmd = cmd;
+
+    ipmbBuffer->Header.Resp.checksum1 = ipmbChecksumCompute(
+        buffer.data(), ipmbConnectionHeaderLength - ipmbChecksumSize);
+
+    if (data.size() > 0)
+    {
+        std::copy(data.begin(), data.end(), ipmbBuffer->Header.Req.data);
+    }
+
+    buffer[bufferLength - ipmbChecksumSize] =
+        ipmbChecksumCompute(buffer.data() + ipmbChecksum2StartOffset,
+                            (ipmbRequestDataHeaderLength + data.size()));
+
+    return 0;
+}
+
+std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
+    IpmbRequest::returnMatchedResponse()
+{
+    return std::make_tuple(
+        static_cast<int>(ipmbResponseStatus::success), matchedResponse->netFn,
+        matchedResponse->rsLun, matchedResponse->cmd,
+        matchedResponse->completionCode, matchedResponse->data);
+}
+
+static std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
+    returnStatus(ipmbResponseStatus status)
+{
+    // we only want to send status here, other fields are not relevant
+    return std::make_tuple(static_cast<int>(status), 0, 0, 0, 0,
+                           std::vector<uint8_t>(0));
+}
+
+// TODO w/a to differentiate channel origin of incoming IPMI response: saving
+// channel number at two oldest unused bits of seq
+void IpmbRequest::addChannelToSeq(const ipmbChannelType &channelType)
+{
+    uint8_t newSeq = (seq | ((static_cast<uint8_t>(channelType) & 0x3) << 6));
+    seq = newSeq;
+}
+
+/**
+ * @brief Ipmb response class methods
+ */
+IpmbResponse::IpmbResponse()
+{
+    data.reserve(ipmbMaxDataSize);
+}
+
+IpmbResponse::IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun,
+                           uint8_t rsSA, uint8_t seq, uint8_t rsLun,
+                           uint8_t cmd, uint8_t completionCode,
+                           std::vector<uint8_t> &inputData) :
+    address(address),
+    netFn(netFn), rqLun(rqLun), rsSA(rsSA), seq(seq), rsLun(rsLun), cmd(cmd),
+    completionCode(completionCode)
+{
+    data.reserve(ipmbMaxDataSize);
+
+    if (inputData.size() > 0)
+    {
+        data = std::move(inputData);
+    }
+}
+
+void IpmbResponse::i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer,
+                                      size_t bufferLength)
+{
+    netFn = ipmbNetFnGet(ipmbBuffer->Header.Resp.rqNetFnLUN);
+    rqLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Resp.rqNetFnLUN);
+    rsSA = ipmbBuffer->Header.Resp.rsSA;
+    seq = ipmbSeqGet(ipmbBuffer->Header.Resp.rsSeqLUN);
+    rsLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Resp.rsSeqLUN);
+    cmd = ipmbBuffer->Header.Resp.cmd;
+    completionCode = ipmbBuffer->Header.Resp.completionCode;
+
+    size_t dataLength =
+        bufferLength - (ipmbConnectionHeaderLength +
+                        ipmbResponseDataHeaderLength + ipmbChecksumSize);
+
+    if (dataLength > 0)
+    {
+        data.insert(data.end(), ipmbBuffer->Header.Resp.data,
+                    &ipmbBuffer->Header.Resp.data[dataLength]);
+    }
+}
+
+int IpmbResponse::ipmbToi2cConstruct(std::vector<uint8_t> &buffer)
+{
+    size_t bufferLength = data.size() + ipmbResponseDataHeaderLength +
+                          ipmbConnectionHeaderLength + ipmbChecksumSize;
+
+    if (bufferLength > ipmbMaxFrameLength)
+    {
+        return -1;
+    }
+
+    buffer.resize(bufferLength);
+    auto ipmbBuffer = reinterpret_cast<IPMB_HEADER *>(buffer.data());
+
+    ipmbBuffer->Header.Resp.address = address;
+    ipmbBuffer->Header.Resp.rqNetFnLUN = ipmbNetFnLunSet(netFn, rqLun);
+    ipmbBuffer->Header.Resp.rsSA = rsSA;
+    ipmbBuffer->Header.Resp.rsSeqLUN = ipmbSeqLunSet(seq, rsLun);
+    ipmbBuffer->Header.Resp.cmd = cmd;
+    ipmbBuffer->Header.Resp.completionCode = completionCode;
+
+    ipmbBuffer->Header.Resp.checksum1 = ipmbChecksumCompute(
+        buffer.data(), ipmbConnectionHeaderLength - ipmbChecksumSize);
+
+    if (data.size() > 0)
+    {
+        std::copy(data.begin(), data.end(), ipmbBuffer->Header.Resp.data);
+    }
+
+    buffer[bufferLength - ipmbChecksumSize] =
+        ipmbChecksumCompute(buffer.data() + ipmbChecksum2StartOffset,
+                            (ipmbResponseDataHeaderLength + data.size()));
+
+    return 0;
+}
+
+bool IpmbCommandFilter::isBlocked(const uint8_t reqNetFn, const uint8_t cmd)
+{
+    auto blockedCmd = unhandledCommands.find({reqNetFn, cmd});
+
+    if (blockedCmd != unhandledCommands.end())
+    {
+        return true;
+    }
+
+    return false;
+}
+
+void IpmbCommandFilter::addFilter(const uint8_t reqNetFn, const uint8_t cmd)
+{
+    if (unhandledCommands.insert({reqNetFn, cmd}).second)
+    {
+        phosphor::logging::log<phosphor::logging::level::INFO>(
+            "addFilter: added command to filter",
+            phosphor::logging::entry("netFn = %d", reqNetFn),
+            phosphor::logging::entry("cmd = %d", cmd));
+    }
+}
+
+/**
+ * @brief Ipmb channel
+ */
+void IpmbChannel::ipmbResponseSend(std::shared_ptr<std::vector<uint8_t>> buffer,
+                                   size_t retriesAttempted = 0)
+{
+    boost::asio::async_write(
+        i2cMasterSocket,
+        boost::asio::buffer(buffer->data() + ipmbAddressSize,
+                            buffer->size() - ipmbAddressSize),
+        [this, buffer, retriesAttempted](const boost::system::error_code ec,
+                                         size_t bytesSent) {
+            if (ec)
+            {
+                size_t currentRetryCnt = retriesAttempted;
+
+                if (currentRetryCnt > ipmbI2cNumberOfRetries)
+                {
+                    phosphor::logging::log<phosphor::logging::level::ERR>(
+                        "ipmbResponseSend: sent to I2C failed after retries");
+                    return;
+                }
+                currentRetryCnt++;
+                ipmbResponseSend(buffer, currentRetryCnt);
+            }
+        });
+}
+
+/**
+ * @brief Ipmb Outstanding Requests
+ */
+void IpmbChannel::makeRequestInvalid(IpmbRequest &request)
+{
+    // change request state to invalid and remove it from outstanding requests
+    // list
+    request.state = ipmbRequestState::invalid;
+    outstandingRequests[request.seq] = nullptr;
+}
+
+void IpmbChannel::makeRequestValid(std::shared_ptr<IpmbRequest> request)
+{
+    // change request state to valid and add it to outstanding requests list
+    request->state = ipmbRequestState::valid;
+    outstandingRequests[request->seq] = request;
+}
+
+bool IpmbChannel::seqNumGet(uint8_t &seq)
+{
+    static uint8_t seqNum = 0;
+
+    for (int i = 0; i < ipmbMaxOutstandingRequestsCount; i++)
+    {
+        seqNum = ++seqNum & ipmbSeqMask;
+        if (seqNum == ipmbMaxOutstandingRequestsCount)
+        {
+            seqNum = 0;
+        }
+
+        if (outstandingRequests[seqNum] == nullptr)
+        {
+            seq = seqNum;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void IpmbChannel::responseMatch(std::unique_ptr<IpmbResponse> &response)
+{
+    std::shared_ptr<IpmbRequest> request = outstandingRequests[response->seq];
+
+    if (request != nullptr)
+    {
+        if (((ipmbRespNetFn(request->netFn)) == (response->netFn)) &&
+            ((request->rqLun) == (response->rqLun)) &&
+            ((request->rsLun) == (response->rsLun)) &&
+            ((request->cmd) == (response->cmd)))
+        {
+            // match, response is corresponding to previously sent request
+            request->state = ipmbRequestState::matched;
+            request->timer->cancel();
+            request->matchedResponse = std::move(response);
+        }
+    }
+}
+
+void IpmbChannel::processI2cEvent()
+{
+    std::array<uint8_t, ipmbMaxFrameLength> buffer{};
+    auto ipmbFrame = reinterpret_cast<IPMB_HEADER *>(buffer.data());
+
+    lseek(ipmbi2cSlaveFd, 0, SEEK_SET);
+    int r = read(ipmbi2cSlaveFd, buffer.data(), ipmbMaxFrameLength);
+    if ((r < ipmbMinFrameLength) || (r > ipmbMaxFrameLength))
+    {
+        goto end;
+    }
+
+    // valiate the frame
+    if (!isFrameValid(ipmbFrame, r))
+    {
+        goto end;
+    }
+
+    // copy frame to ipmib message buffer
+    if (ipmbIsResponse(ipmbFrame))
+    {
+        std::unique_ptr<IpmbResponse> ipmbMessageReceived =
+            std::make_unique<IpmbResponse>();
+
+        ipmbMessageReceived->i2cToIpmbConstruct(ipmbFrame, r);
+
+        // try to match response with outstanding request
+        responseMatch(ipmbMessageReceived);
+    }
+    else
+    {
+        // if command is blocked - respond with 'invalid command'
+        // completion code
+        if (commandFilter)
+        {
+            uint8_t netFn = ipmbNetFnGet(ipmbFrame->Header.Req.rsNetFnLUN);
+            uint8_t cmd = ipmbFrame->Header.Req.cmd;
+
+            if (commandFilter->isBlocked(netFn, cmd))
+            {
+                uint8_t seq = ipmbSeqGet(ipmbFrame->Header.Req.rqSeqLUN);
+                uint8_t lun =
+                    ipmbLunFromSeqLunGet(ipmbFrame->Header.Req.rqSeqLUN);
+                std::vector<uint8_t> data;
+
+                // prepare generic response
+                auto ipmbResponse =
+                    IpmbResponse(ipmbRqSlaveAddress, ipmbRespNetFn(netFn), lun,
+                                 ipmbBmcSlaveAddress, seq, ipmbRsLun, cmd,
+                                 ipmbIpmiInvalidCommand, data);
+
+                std::shared_ptr<std::vector<uint8_t>> buffer =
+                    std::make_shared<std::vector<uint8_t>>();
+
+                if (ipmbResponse.ipmbToi2cConstruct(*buffer) == 0)
+                {
+                    ipmbResponseSend(buffer);
+                }
+
+                goto end;
+            }
+        }
+
+        auto ipmbMessageReceived = IpmbRequest();
+
+        ipmbMessageReceived.i2cToIpmbConstruct(ipmbFrame, r);
+
+        // TODO w/a to differentiate channel origin of incoming IPMI
+        // response: extracting channel number from seq
+        ipmbMessageReceived.addChannelToSeq(getChannelType());
+
+        // send request to the client
+        ipmbMessageReceived.incomingMessageHandler();
+    }
+
+end:
+    i2cSlaveSocket.async_wait(
+        boost::asio::ip::tcp::socket::wait_error,
+        [this](const boost::system::error_code &ec) {
+            if (ec)
+            {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    "Error: processI2cEvent()");
+                return;
+            }
+
+            processI2cEvent();
+        });
+}
+
+IpmbChannel::IpmbChannel(boost::asio::io_service &io,
+                         uint8_t ipmbBmcSlaveAddress,
+                         uint8_t ipmbRqSlaveAddress, ipmbChannelType type,
+                         std::shared_ptr<IpmbCommandFilter> commandFilter) :
+    i2cSlaveSocket(io),
+    i2cMasterSocket(io), ipmbBmcSlaveAddress(ipmbBmcSlaveAddress),
+    ipmbRqSlaveAddress(ipmbRqSlaveAddress), type(type),
+    commandFilter(commandFilter)
+{
+}
+
+int IpmbChannel::ipmbChannelInit(const char *ipmbI2cSlave,
+                                 const char *ipmbI2cMaster)
+{
+    // open fd to i2c slave device
+    ipmbi2cSlaveFd = open(ipmbI2cSlave, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+    if (ipmbi2cSlaveFd < 0)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "ipmbChannelInit: error opening ipmbI2cSlave");
+        return -1;
+    }
+
+    // open fd to i2c master device
+    ipmbi2cMasterFd = open(ipmbI2cMaster, O_RDWR | O_NONBLOCK);
+    if (ipmbi2cMasterFd < 0)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "ipmbChannelInit: error opening ipmbI2cMaster");
+        close(ipmbi2cSlaveFd);
+        return -1;
+    }
+
+    // set slave address of recipient
+    if (ioctl(ipmbi2cMasterFd, I2C_SLAVE,
+              ipmbAddressTo7BitSet(ipmbRqSlaveAddress)) < 0)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "ipmbChannelInit: error setting ipmbi2cMasterFd slave address");
+        close(ipmbi2cSlaveFd);
+        close(ipmbi2cMasterFd);
+        return -1;
+    }
+
+    i2cMasterSocket.assign(ipmbi2cMasterFd);
+    i2cSlaveSocket.assign(boost::asio::ip::tcp::v4(), ipmbi2cSlaveFd);
+    i2cSlaveSocket.async_wait(
+        boost::asio::ip::tcp::socket::wait_error,
+        [this](const boost::system::error_code &ec) {
+            if (ec)
+            {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    "Error: processI2cEvent()");
+                return;
+            }
+
+            processI2cEvent();
+        });
+
+    return 0;
+}
+
+uint8_t IpmbChannel::getBmcSlaveAddress()
+{
+    return ipmbBmcSlaveAddress;
+}
+
+uint8_t IpmbChannel::getRqSlaveAddress()
+{
+    return ipmbRqSlaveAddress;
+}
+
+ipmbChannelType IpmbChannel::getChannelType()
+{
+    return type;
+}
+
+void IpmbChannel::addFilter(const uint8_t respNetFn, const uint8_t cmd)
+{
+    if (commandFilter)
+    {
+        commandFilter->addFilter(respNetFn, cmd);
+    }
+}
+
+std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
+    IpmbChannel::requestAdd(boost::asio::yield_context &yield,
+                            std::shared_ptr<IpmbRequest> request)
+{
+    makeRequestValid(request);
+
+    std::vector<uint8_t> buffer(0);
+    if (request->ipmbToi2cConstruct(buffer) != 0)
+    {
+        return returnStatus(ipmbResponseStatus::error);
+    }
+
+    for (int i = 0; i < ipmbNumberOfTries; i++)
+    {
+        boost::system::error_code ec;
+
+        for (int j = 0; j < ipmbI2cNumberOfRetries; j++)
+        {
+            boost::asio::async_write(
+                i2cMasterSocket,
+                boost::asio::buffer(buffer.data() + ipmbAddressSize,
+                                    buffer.size() - ipmbAddressSize),
+                yield[ec]);
+
+            if (ec)
+            {
+                phosphor::logging::log<phosphor::logging::level::INFO>(
+                    "requestAdd: Sent to I2C failed");
+                continue;
+            }
+            break;
+        }
+
+        request->timer->expires_after(
+            std::chrono::milliseconds(ipmbRequestRetryTimeout));
+        request->timer->async_wait(yield[ec]);
+
+        if (ec && ec != boost::asio::error::operation_aborted)
+        {
+            // unexpected error - invalidate request and return generic error
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "requestAdd: async_wait error");
+            makeRequestInvalid(*request);
+            return returnStatus(ipmbResponseStatus::error);
+        }
+
+        if (request->state == ipmbRequestState::matched)
+        {
+            // matched response, send it to client application
+            makeRequestInvalid(*request);
+            return request->returnMatchedResponse();
+        }
+    }
+
+    makeRequestInvalid(*request);
+    return returnStatus(ipmbResponseStatus::timeout);
+}
+
+static IpmbChannel *getChannel(ipmbChannelType channelType)
+{
+    auto channel =
+        std::find_if(ipmbChannels.begin(), ipmbChannels.end(),
+                     [channelType](IpmbChannel &channel) {
+                         return channel.getChannelType() == channelType;
+                     });
+    if (channel != ipmbChannels.end())
+    {
+        return &(*channel);
+    }
+
+    return nullptr;
+}
+
+static int initializeChannels()
+{
+    std::shared_ptr<IpmbCommandFilter> commandFilter =
+        std::make_shared<IpmbCommandFilter>();
+
+    for (const auto &channelConfig : ipmbChannelsConfig)
+    {
+        auto channel = ipmbChannels.emplace(ipmbChannels.end(), io,
+                                            channelConfig.ipmbBmcSlaveAddress,
+                                            channelConfig.ipmbRqSlaveAddress,
+                                            channelConfig.type, commandFilter);
+
+        if (channel->ipmbChannelInit(channelConfig.ipmbI2cSlave,
+                                     channelConfig.ipmbI2cMaster) < 0)
+        {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "initializeChannels: channel initialization failed");
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * @brief Dbus callbacks
+ */
+auto ipmbSendMessage = [](uint8_t seq, uint8_t netfn, uint8_t lun, uint8_t cmd,
+                          uint8_t cc, std::vector<uint8_t> &dataReceived) {
+    int64_t status = -1;
+    std::shared_ptr<std::vector<uint8_t>> buffer =
+        std::make_shared<std::vector<uint8_t>>();
+
+    if (dataReceived.size() > ipmbMaxDataSize)
+    {
+        return status;
+    }
+
+    if (netfn & ipmbNetFnResponseMask)
+    {
+        IpmbChannel *channel = getChannel(getChannelFromSeq(seq));
+        if (channel == nullptr)
+        {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "ipmbSendMessage: channel does not exist");
+            return status;
+        }
+
+        // if command is not supported, add it to filter
+        if (cc == ipmbIpmiInvalidCommand)
+        {
+            channel->addFilter(ipmbReqNetFnFromRespNetFn(netfn), cmd);
+        }
+
+        uint8_t rqSlaveAddress = channel->getRqSlaveAddress();
+        uint8_t bmcSlaveAddress = channel->getBmcSlaveAddress();
+
+        // response received
+        // dataReceived is empty after constructor invocation
+        std::unique_ptr<IpmbResponse> ipmbMessageReceived =
+            std::make_unique<IpmbResponse>(rqSlaveAddress, netfn, lun,
+                                           bmcSlaveAddress, seq, lun, cmd, cc,
+                                           dataReceived);
+
+        status = ipmbMessageReceived->ipmbToi2cConstruct(*buffer);
+        if (status != 0)
+        {
+            return status;
+        }
+
+        channel->ipmbResponseSend(buffer);
+        return status;
+    }
+
+    // we are not expecting request here
+    phosphor::logging::log<phosphor::logging::level::ERR>(
+        "ipmbSendMessage: got a request");
+    return status;
+};
+
+auto ipmbHandleRequest = [](boost::asio::yield_context yield,
+                            uint8_t reqChannel, uint8_t netfn, uint8_t lun,
+                            uint8_t cmd, std::vector<uint8_t> dataReceived) {
+    IpmbChannel *channel = getChannel(static_cast<ipmbChannelType>(reqChannel));
+    if (channel == nullptr)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "ipmbHandleRequest: requested channel does not exist");
+        return returnStatus(ipmbResponseStatus::invalid_param);
+    }
+
+    // check outstanding request list for valid sequence number
+    uint8_t seqNum = 0;
+    bool seqValid = channel->seqNumGet(seqNum);
+    if (!seqValid)
+    {
+        phosphor::logging::log<phosphor::logging::level::WARNING>(
+            "ipmbHandleRequest: cannot add more requests to the list");
+        return returnStatus(ipmbResponseStatus::busy);
+    }
+
+    uint8_t bmcSlaveAddress = channel->getBmcSlaveAddress();
+    uint8_t rqSlaveAddress = channel->getRqSlaveAddress();
+
+    // construct the request to add it to outstanding request list
+    std::shared_ptr<IpmbRequest> request = std::make_shared<IpmbRequest>(
+        rqSlaveAddress, netfn, ipmbRsLun, bmcSlaveAddress, seqNum, lun, cmd,
+        dataReceived);
+
+    if (!request->timer)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "ipmbHandleRequest: timer object does not exist");
+        return returnStatus(ipmbResponseStatus::error);
+    }
+
+    return channel->requestAdd(yield, request);
+};
+
+/**
+ * @brief Main
+ */
+int main(int argc, char *argv[])
+{
+    conn->request_name(ipmbBus);
+
+    auto server = sdbusplus::asio::object_server(conn);
+
+    std::shared_ptr<sdbusplus::asio::dbus_interface> ipmiIface =
+        server.add_interface(ipmbObj, hostIpmiIntf);
+    std::shared_ptr<sdbusplus::asio::dbus_interface> ipmbIface =
+        server.add_interface(ipmbObj, ipmbDbusIntf);
+
+    ipmiIface->register_method("sendMessage", std::move(ipmbSendMessage));
+    ipmbIface->register_method("sendRequest", std::move(ipmbHandleRequest));
+    ipmiIface->initialize();
+    ipmbIface->initialize();
+
+    if (initializeChannels() < 0)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "Error initializeChannels");
+        return -1;
+    }
+
+    io.run();
+    return 0;
+}
diff --git a/ipmbbridged.hpp b/ipmbbridged.hpp
new file mode 100644
index 0000000..c139391
--- /dev/null
+++ b/ipmbbridged.hpp
@@ -0,0 +1,331 @@
+/* Copyright 2018 Intel
+ *
+ * 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 "ipmbdefines.hpp"
+
+#include <boost/container/flat_set.hpp>
+#include <optional>
+#include <sdbusplus/asio/object_server.hpp>
+#include <sdbusplus/message.hpp>
+#include <vector>
+
+#ifndef IPMBBRIDGED_HPP
+#define IPMBBRIDGED_HPP
+
+/**
+ * @brief Ipmb return status codes (sendRequest API call)
+ */
+enum class ipmbResponseStatus
+{
+    success = 0,
+    error = 1,
+    invalid_param = 2,
+    busy = 3,
+    timeout = 4,
+};
+
+/**
+ * @brief Ipmb outstanding requests defines
+ */
+constexpr int ipmbMaxOutstandingRequestsCount = 64;
+constexpr int ipmbNumberOfTries = 6;
+constexpr uint64_t ipmbRequestRetryTimeout = 250; // ms
+
+/**
+ * @brief Ipmb I2C communication
+ */
+constexpr uint8_t ipmbI2cNumberOfRetries = 2;
+
+/**
+ * @brief Ipmb defines
+ */
+constexpr size_t ipmbMaxDataSize = 256;
+constexpr size_t ipmbConnectionHeaderLength = 3;
+constexpr size_t ipmbResponseDataHeaderLength = 4;
+constexpr size_t ipmbRequestDataHeaderLength = 3;
+constexpr size_t ipmbAddressSize = 1;
+constexpr size_t ipmbChecksumSize = 1;
+constexpr size_t ipmbChecksum2StartOffset = 3;
+constexpr size_t ipmbMinFrameLength = 7;
+constexpr size_t ipmbMaxFrameLength = ipmbConnectionHeaderLength +
+                                      ipmbResponseDataHeaderLength +
+                                      ipmbChecksumSize + ipmbMaxDataSize;
+
+/**
+ * @brief Ipmb misc
+ */
+constexpr uint8_t ipmbNetFnResponseMask = 0x01;
+constexpr uint8_t ipmbLunMask = 0x03;
+constexpr uint8_t ipmbSeqMask = 0x3F;
+constexpr uint8_t ipmbRsLun = 0x0;
+
+/**
+ * @brief Ipmb setters
+ */
+constexpr uint8_t ipmbNetFnLunSet(uint8_t netFn, uint8_t lun)
+{
+    return ((netFn << 2) | (lun & ipmbLunMask));
+}
+
+constexpr uint8_t ipmbSeqLunSet(uint8_t seq, uint8_t lun)
+{
+    return ((seq << 2) | (lun & ipmbLunMask));
+}
+
+constexpr uint8_t ipmbAddressTo7BitSet(uint8_t address)
+{
+    return address >> 1;
+}
+
+constexpr uint8_t ipmbRespNetFn(uint8_t netFn)
+{
+    return netFn |= 1;
+}
+
+/**
+ * @brief Ipmb getters
+ */
+constexpr uint8_t ipmbNetFnGet(uint8_t netFnLun)
+{
+    return netFnLun >> 2;
+}
+
+constexpr uint8_t ipmbLunFromNetFnLunGet(uint8_t netFnLun)
+{
+    return netFnLun & ipmbLunMask;
+}
+
+constexpr uint8_t ipmbSeqGet(uint8_t seqNumLun)
+{
+    return seqNumLun >> 2;
+}
+
+constexpr uint8_t ipmbLunFromSeqLunGet(uint8_t seqNumLun)
+{
+    return seqNumLun & ipmbLunMask;
+}
+
+/**
+ * @brief Ipmb checkers
+ */
+constexpr bool ipmbIsResponse(IPMB_HEADER *ipmbHeader)
+{
+    return ipmbNetFnGet(ipmbHeader->Header.Resp.rqNetFnLUN) &
+           ipmbNetFnResponseMask;
+}
+
+/**
+ * @brief Ipmb request state
+ */
+enum class ipmbRequestState
+{
+    invalid,
+    valid,
+    matched,
+};
+
+/**
+ * @brief Channel types
+ */
+enum class ipmbChannelType
+{
+    ipmb = 0,
+    me = 1
+};
+
+/**
+ * @brief Channel configuration structure
+ */
+struct IpmbChannelConfig
+{
+    ipmbChannelType type;
+    const char *ipmbI2cSlave;
+    const char *ipmbI2cMaster;
+    uint8_t ipmbBmcSlaveAddress;
+    uint8_t ipmbRqSlaveAddress;
+};
+
+// TODO w/a to differentiate channel origin of incoming IPMI response:
+// extracting channel number from 2 oldest bits of seq
+constexpr ipmbChannelType getChannelFromSeq(const uint8_t &seq)
+{
+    return static_cast<ipmbChannelType>((seq & 0xC0) >> 6);
+}
+
+/**
+ * @brief IpmbResponse declaration
+ */
+struct IpmbResponse
+{
+    uint8_t address;
+    uint8_t netFn;
+    uint8_t rqLun;
+    uint8_t rsSA;
+    uint8_t seq;
+    uint8_t rsLun;
+    uint8_t cmd;
+    uint8_t completionCode;
+    std::vector<uint8_t> data;
+
+    IpmbResponse();
+
+    IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA,
+                 uint8_t seq, uint8_t rsLun, uint8_t cmd,
+                 uint8_t completionCode, std::vector<uint8_t> &inputData);
+
+    void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
+
+    int ipmbToi2cConstruct(std::vector<uint8_t> &buffer);
+};
+
+/**
+ * @brief IpmbRequest declaration
+ */
+struct IpmbRequest
+{
+    uint8_t address;
+    uint8_t netFn;
+    uint8_t rsLun;
+    uint8_t rqSA;
+    uint8_t seq;
+    uint8_t rqLun;
+    uint8_t cmd;
+    std::vector<uint8_t> data;
+
+    size_t dataLength;
+    ipmbRequestState state;
+    std::optional<boost::asio::steady_timer> timer;
+    std::unique_ptr<IpmbResponse> matchedResponse;
+
+    // creates empty request with empty timer object
+    IpmbRequest();
+
+    IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun, uint8_t rqSA,
+                uint8_t seq, uint8_t rqLun, uint8_t cmd,
+                std::vector<uint8_t> &inputData);
+
+    IpmbRequest(const IpmbRequest &) = delete;
+    IpmbRequest &operator=(IpmbRequest const &) = delete;
+
+    void incomingMessageHandler();
+
+    std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
+        returnMatchedResponse();
+
+    std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
+        returnStatusResponse(int status);
+
+    void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
+
+    int ipmbToi2cConstruct(std::vector<uint8_t> &buffer);
+
+    // TODO w/a to differentiate channel origin of incoming IPMI response:
+    // saving channel number at two oldest unused bits of seq
+    void addChannelToSeq(const ipmbChannelType &channelType);
+};
+
+/**
+ * @brief Command filtering class declaration
+ *
+ * This feature provides simple mechanism for filtering out commands - which are
+ * not implemented in IPMI - on IPMB level, in order to reduce DBus traffic
+ */
+class IpmbCommandFilter
+{
+  public:
+    // function checking if netFn & cmd combination exist in blocked command
+    // list
+    bool isBlocked(const uint8_t reqNetFn, const uint8_t cmd);
+    // function adding netfFn & cmd combination to the blocked command list
+    void addFilter(const uint8_t reqNetFn, const uint8_t cmd);
+
+  private:
+    boost::container::flat_set<std::pair<uint8_t, uint8_t>> unhandledCommands;
+};
+
+/**
+ * @brief Command filtering defines
+ */
+
+constexpr uint8_t ipmbIpmiInvalidCommand = 0xC1;
+
+constexpr uint8_t ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn)
+{
+    return reqNetFn & ~ipmbNetFnResponseMask;
+}
+
+/**
+ * @brief IpmbChannel class declaration
+ */
+class IpmbChannel
+{
+  public:
+    IpmbChannel(boost::asio::io_service &io, uint8_t ipmbBmcSlaveAddress,
+                uint8_t ipmbRqSlaveAddress, ipmbChannelType type,
+                std::shared_ptr<IpmbCommandFilter> commandFilter);
+
+    IpmbChannel(const IpmbChannel &) = delete;
+    IpmbChannel &operator=(IpmbChannel const &) = delete;
+
+    int ipmbChannelInit(const char *ipmbI2cSlave, const char *ipmbI2cMaster);
+
+    bool seqNumGet(uint8_t &seq);
+
+    ipmbChannelType getChannelType();
+
+    uint8_t getBmcSlaveAddress();
+
+    uint8_t getRqSlaveAddress();
+
+    void addFilter(const uint8_t respNetFn, const uint8_t cmd);
+
+    void processI2cEvent();
+
+    void ipmbResponseSend(std::shared_ptr<std::vector<uint8_t>> buffer,
+                          size_t retriesAttempted);
+
+    std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
+        requestAdd(boost::asio::yield_context &yield,
+                   std::shared_ptr<IpmbRequest> requestToSend);
+
+  private:
+    boost::asio::ip::tcp::socket i2cSlaveSocket;
+    boost::asio::posix::stream_descriptor i2cMasterSocket;
+
+    int ipmbi2cMasterFd;
+    int ipmbi2cSlaveFd;
+
+    uint8_t ipmbBmcSlaveAddress;
+    uint8_t ipmbRqSlaveAddress;
+
+    ipmbChannelType type;
+
+    std::shared_ptr<IpmbCommandFilter> commandFilter;
+
+    // array storing outstanding requests
+    std::array<std::shared_ptr<IpmbRequest>, ipmbMaxOutstandingRequestsCount>
+        outstandingRequests;
+
+    void requestTimerCallback(std::shared_ptr<IpmbRequest> request,
+                              std::shared_ptr<std::vector<uint8_t>> buffer);
+
+    void responseMatch(std::unique_ptr<IpmbResponse> &response);
+
+    void makeRequestInvalid(IpmbRequest &request);
+
+    void makeRequestValid(std::shared_ptr<IpmbRequest> request);
+};
+
+#endif
diff --git a/ipmbdefines.hpp b/ipmbdefines.hpp
new file mode 100644
index 0000000..3797e92
--- /dev/null
+++ b/ipmbdefines.hpp
@@ -0,0 +1,64 @@
+/* Copyright 2018 Intel
+ *
+ * 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.
+ */
+
+#ifndef IPMBDEFINES_HPP
+#define IPMBDEFINES_HPP
+
+#include <inttypes.h>
+
+#pragma pack(1)
+typedef struct _IPMB_HEADER
+{
+    union
+    {
+        struct
+        {
+            /** @brief IPMB Connection Header Format */
+            uint8_t address;
+            uint8_t rsNetFnLUN; /// @brief responder's net function and logical
+                                /// unit number
+            uint8_t checksum1;  /// @brief checksum computed on first two bytes
+                                /// of IPMB_HEADER
+            /** @brief IPMB Header */
+            uint8_t rqSA;     /// @brief requester's slave address, LS bit=0
+            uint8_t rqSeqLUN; /// @brief requester's sequence number and logical
+                              /// unit number
+            uint8_t cmd; /// @brief command required by the network identify the
+                         /// type of rqts
+            uint8_t data[]; /// @brief payload
+        } Req;              /// @brief IPMB request header
+        struct
+        {
+            uint8_t address;
+            /** @brief IPMB Connection Header Format */
+            uint8_t rqNetFnLUN; /// @brief requester's net function and logical
+                                /// unit number
+            uint8_t checksum1;  /// @brief checksum computed on first two bytes
+                                /// of IPMB_HEADER
+            /** @brief IPMB Header */
+            uint8_t rsSA;     /// @brief responder's slave address, LS bit=0
+            uint8_t rsSeqLUN; /// @brief responder's sequence number and logical
+                              /// unit number
+            uint8_t cmd; /// @brief command required by the network identify the
+                         /// type of rqts
+            uint8_t completionCode; /// @brief IPMB nodes return a Completion
+                                    /// Code in all response msgs
+            uint8_t data[];         /// @brief payload
+        } Resp;                     /// @brief IPMB response header
+    } Header;                       /// @brief IPMB frame header
+} IPMB_HEADER;
+#pragma pack()
+
+#endif
diff --git a/ipmbutils.cpp b/ipmbutils.cpp
new file mode 100644
index 0000000..d9a440e
--- /dev/null
+++ b/ipmbutils.cpp
@@ -0,0 +1,90 @@
+/* Copyright 2018 Intel
+ *
+ * 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 "ipmbbridged.hpp"
+#include "ipmbdefines.hpp"
+
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/**
+ * @brief Ipmb utils for checksum
+ */
+bool ipmbChecksumValidate(uint8_t *data, uint8_t length)
+{
+    uint8_t checksum = 0;
+
+    // compute checksum.
+    for (uint8_t idx = 0; idx < length; idx++)
+    {
+        checksum += data[idx];
+    }
+
+    // check if checksum is valid.
+    if (0 == checksum)
+    {
+        // checksum valid.
+        return true;
+    }
+    else
+    {
+        // checksum invalid.
+        return false;
+    }
+}
+
+uint8_t ipmbChecksumCompute(uint8_t *data, uint8_t length)
+{
+    uint8_t checksum = 0;
+
+    // compute checksum.
+    for (uint8_t idx = 0; idx < length; idx++)
+    {
+        checksum += data[idx];
+    }
+
+    checksum = (~checksum) + 1;
+
+    // return computed checksum value.
+    return checksum;
+}
+
+inline bool ipmbConnectionHeaderChecksumValidate(IPMB_HEADER *ipmbHeader)
+{
+    return ipmbChecksumValidate(reinterpret_cast<uint8_t *>(ipmbHeader),
+                                ipmbConnectionHeaderLength);
+}
+
+inline bool ipmbDataChecksumValidate(IPMB_HEADER *ipmbHeader, uint8_t length)
+{
+    return ipmbChecksumValidate(
+        (reinterpret_cast<uint8_t *>(ipmbHeader) + ipmbConnectionHeaderLength),
+        (length - ipmbConnectionHeaderLength));
+}
+
+bool isFrameValid(IPMB_HEADER *frame, uint8_t length)
+{
+    bool frameValid = ipmbConnectionHeaderChecksumValidate(frame);
+    if (false == frameValid)
+    {
+        // invalid connection header checksum.
+        return false;
+    }
+
+    // data checksum validation.
+    return ipmbDataChecksumValidate(frame, length);
+}
diff --git a/ipmbutils.hpp b/ipmbutils.hpp
new file mode 100644
index 0000000..b6c2139
--- /dev/null
+++ b/ipmbutils.hpp
@@ -0,0 +1,29 @@
+/* Copyright 2018 Intel
+ *
+ * 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.
+ */
+
+#ifndef IPMBUTILS_HPP
+#define IPMBUTILS_HPP
+
+/**
+ * @brief function performing IPMB header and data checksum validation
+ */
+bool isFrameValid(IPMB_HEADER *frame, uint8_t length);
+
+/**
+ * @brief function computing IPMB layer checksum
+ */
+uint8_t ipmbChecksumCompute(uint8_t *data, uint8_t length);
+
+#endif