Add ipmi OEM handler to get the BMC mode

The response can indicate one of the BMC mode
below
0 -> Non Bare Metal Mode
1 -> Bare Metal Mode
2 -> Bare Metal Cleaning Mode

The Bare Metal Cleaning Mode is not
yet supported

Tested:

Response in BM Mode

ipmitool raw 0x2e 0x32 0x79 0x2b 0x00 0x10
79 2b 00 14 01

Response in  Non-BM Mode

ipmitool raw 0x2e 0x32 0x79 0x2b 0x00 0x10
79 2b 00 14 00

Signed-off-by: Nikhil Namjoshi <nikhilnamjoshi@google.com>
Change-Id: I34474fd04f9aed35bd71725805ed52a5df8ab8c9
diff --git a/README.md b/README.md
index 95ec033..d6157c9 100644
--- a/README.md
+++ b/README.md
@@ -419,3 +419,20 @@
 |0x00|0x0F|Subcommand
 |0x01|Config length (N)|Number of bytes needed for the bifurcation config
 |0x02..0x02 + N - 1|Lanes per device|Each byte represents the number of lanes bonded together for each endpoint device
+
+### GetBmcMode - SubCommand 0x10
+
+Request the operational mode of the BMC.
+
+Request
+
+|Byte(s) |Value |Data
+|--------|------|----
+|0x00|0x10|Subcommand
+
+Response
+
+|Byte(s) |Value |Data
+|--------|------|----
+|0x00|0x10|Subcommand
+|0x01|Current BMC MODE|<ul><li>0 -> Non Bare Metal Mode</li><li>1 -> Bare Metal Mode</li><li>2 -> Bare Metal Cleaning Mode</li></ul>
diff --git a/bmc_mode.cpp b/bmc_mode.cpp
new file mode 100644
index 0000000..b3af71d
--- /dev/null
+++ b/bmc_mode.cpp
@@ -0,0 +1,44 @@
+// Copyright 2022 Google LLC
+//
+// 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 "bmc_mode.hpp"
+
+#include "commands.hpp"
+#include "errors.hpp"
+#include "handler.hpp"
+
+#include <ipmid/api-types.hpp>
+#include <span>
+#include <vector>
+
+namespace google
+{
+namespace ipmi
+{
+
+Resp getBmcMode(std::span<const uint8_t>, HandlerInterface* handler)
+{
+    try
+    {
+        return ::ipmi::responseSuccess(
+            SysOEMCommands::SysGetBmcMode,
+            std::vector<std::uint8_t>{handler->getBmcMode()});
+    }
+    catch (const IpmiException& e)
+    {
+        return ::ipmi::response(e.getIpmiError());
+    }
+}
+} // namespace ipmi
+} // namespace google
diff --git a/bmc_mode.hpp b/bmc_mode.hpp
new file mode 100644
index 0000000..ee80d54
--- /dev/null
+++ b/bmc_mode.hpp
@@ -0,0 +1,32 @@
+// Copyright 2022 Google LLC
+//
+// 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.
+
+#pragma once
+
+#include "handler.hpp"
+
+#include <ipmid/api.h>
+
+#include <ipmid/api-types.hpp>
+#include <span>
+
+namespace google
+{
+namespace ipmi
+{
+
+Resp getBmcMode(std::span<const uint8_t> data, HandlerInterface* handler);
+
+} // namespace ipmi
+} // namespace google
diff --git a/commands.hpp b/commands.hpp
index 7eb668a..86a2650 100644
--- a/commands.hpp
+++ b/commands.hpp
@@ -53,6 +53,8 @@
     SysAccelOobWrite = 14,
     // The Sys PCIe Slot Bifurcation information command.
     SysPCIeSlotBifurcation = 15,
+    // The Sys get BMC Mode command
+    SysGetBmcMode = 16,
 };
 
 } // namespace ipmi
diff --git a/handler.cpp b/handler.cpp
index 6113f5d..161f10d 100644
--- a/handler.cpp
+++ b/handler.cpp
@@ -11,7 +11,6 @@
 // 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 "handler.hpp"
 
 #include "errors.hpp"
@@ -41,6 +40,8 @@
 #include <variant>
 #include <xyz/openbmc_project/Common/error.hpp>
 
+#include "bm_config.h"
+
 #ifndef NCSI_IF_NAME
 #define NCSI_IF_NAME eth0
 #endif
@@ -65,6 +66,28 @@
 using InternalFailure =
     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
 
+enum class BmcMode : uint8_t
+{
+    NON_BM_MODE = 0,
+    BM_MODE,
+    BM_CLEANING_MODE
+};
+
+uint8_t isBmcInBareMetalMode()
+{
+#if BARE_METAL
+    return static_cast<uint8_t>(BmcMode::BM_MODE);
+#else
+    return static_cast<uint8_t>(BmcMode::NON_BM_MODE);
+#endif
+}
+
+uint8_t Handler::getBmcMode()
+{
+    // BM_CLEANING_MODE is not implemented yet
+    return isBmcInBareMetalMode();
+}
+
 std::tuple<std::uint8_t, std::string>
     Handler::getEthDetails(std::string intf) const
 {
diff --git a/handler.hpp b/handler.hpp
index 6057644..9ac3bb7 100644
--- a/handler.hpp
+++ b/handler.hpp
@@ -39,6 +39,13 @@
     virtual ~HandlerInterface() = default;
 
     /**
+     * Return the operation mode of BMC
+     *
+     * @return the BMC operation mode
+     */
+    virtual uint8_t getBmcMode() = 0;
+
+    /**
      * Return ethernet details (hard-coded).
      *
      * @return tuple of ethernet details (channel, if name).
diff --git a/handler_impl.hpp b/handler_impl.hpp
index a088585..33e5592 100644
--- a/handler_impl.hpp
+++ b/handler_impl.hpp
@@ -46,6 +46,7 @@
         bifurcationHelper(bifurcationHelper){};
     ~Handler() = default;
 
+    uint8_t getBmcMode() override;
     std::tuple<std::uint8_t, std::string>
         getEthDetails(std::string intf) const override;
     std::int64_t getRxPackets(const std::string& name) const override;
diff --git a/ipmi.cpp b/ipmi.cpp
index 0638a82..c296e63 100644
--- a/ipmi.cpp
+++ b/ipmi.cpp
@@ -14,6 +14,7 @@
 
 #include "ipmi.hpp"
 
+#include "bmc_mode.hpp"
 #include "cable.hpp"
 #include "commands.hpp"
 #include "cpld.hpp"
@@ -47,6 +48,8 @@
 {
     switch (cmd)
     {
+        case SysGetBmcMode:
+            return getBmcMode(data, handler);
         case SysCableCheck:
             return cableCheck(data, handler);
         case SysCpldVersion:
diff --git a/meson.build b/meson.build
index a2e8d1b..6384f73 100644
--- a/meson.build
+++ b/meson.build
@@ -17,6 +17,12 @@
   output: 'config.h',
   configuration: conf_data)
 
+bm_conf_data = configuration_data()
+bm_conf_data.set10('BARE_METAL', get_option('bare_metal'))
+bm_conf_h = configure_file(
+  output: 'bm_config.h',
+  configuration: bm_conf_data)
+
 meson.get_compiler('cpp').has_header_symbol(
   'ipmid/api.h',
   'ipmid_get_sd_bus_connection')
@@ -55,6 +61,7 @@
 
 sys_lib = static_library(
   'sys',
+  'bmc_mode.cpp',
   'cable.cpp',
   'cpld.cpp',
   'entity_name.cpp',
diff --git a/meson_options.txt b/meson_options.txt
index 45af3e9..a91d641 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,2 +1,3 @@
 option('tests', type: 'feature', description: 'Build tests')
 option('static-bifurcation', type: 'string', value: '/usr/share/google-ipmi-sys/bifurcation.json', description: 'Path to Static Bifurcation Json config')
+option('bare_metal', type: 'boolean', value: false, description: 'Bare Metal Mode Flag')
diff --git a/test/bmc_mode_unittest.cpp b/test/bmc_mode_unittest.cpp
new file mode 100644
index 0000000..a0b5178
--- /dev/null
+++ b/test/bmc_mode_unittest.cpp
@@ -0,0 +1,73 @@
+// Copyright 2022 Google LLC
+//
+// 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 "bmc_mode.hpp"
+#include "commands.hpp"
+#include "handler_mock.hpp"
+#include "helper.hpp"
+
+#include <vector>
+
+#include <gtest/gtest.h>
+
+using ::testing::Return;
+
+namespace google
+{
+namespace ipmi
+{
+
+TEST(BmcModeCommandTest, ValidRequest)
+{
+    std::vector<std::uint8_t> request = {};
+    uint8_t bmcMode = 0; // Non Bare Metal Mode
+
+    HandlerMock hMock;
+    EXPECT_CALL(hMock, getBmcMode()).WillOnce(Return(bmcMode));
+
+    auto reply = getBmcMode(request, &hMock);
+    auto result = ValidateReply(reply);
+    auto& data = result.second;
+
+    EXPECT_EQ(1, data.size());
+    EXPECT_EQ(SysOEMCommands::SysGetBmcMode, result.first);
+    EXPECT_EQ(0, data[0]);
+
+    bmcMode = 1; // Bare Metal Mode
+
+    EXPECT_CALL(hMock, getBmcMode()).WillOnce(Return(bmcMode));
+
+    reply = getBmcMode(request, &hMock);
+    result = ValidateReply(reply);
+    data = result.second;
+
+    EXPECT_EQ(1, data.size());
+    EXPECT_EQ(SysOEMCommands::SysGetBmcMode, result.first);
+    EXPECT_EQ(1, data[0]);
+
+    bmcMode = 2; // Bare Metal Cleaning Mode
+
+    EXPECT_CALL(hMock, getBmcMode()).WillOnce(Return(bmcMode));
+
+    reply = getBmcMode(request, &hMock);
+    result = ValidateReply(reply);
+    data = result.second;
+
+    EXPECT_EQ(1, data.size());
+    EXPECT_EQ(SysOEMCommands::SysGetBmcMode, result.first);
+    EXPECT_EQ(2, data[0]);
+}
+
+} // namespace ipmi
+} // namespace google
diff --git a/test/handler_mock.hpp b/test/handler_mock.hpp
index 9961fa8..580b043 100644
--- a/test/handler_mock.hpp
+++ b/test/handler_mock.hpp
@@ -63,6 +63,7 @@
                 (std::string_view, uint64_t, uint8_t, uint64_t),
                 (const, override));
     MOCK_METHOD(std::vector<uint8_t>, pcieBifurcation, (uint8_t), (override));
+    MOCK_METHOD(uint8_t, getBmcMode, (), (override));
 };
 
 } // namespace ipmi
diff --git a/test/meson.build b/test/meson.build
index f2c11a2..53064a1 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -28,6 +28,7 @@
   'poweroff',
   'psu',
   'pcie_bifurcation',
+  'bmc_mode',
 ]
 
 foreach t : tests