IPMI OEM Get BIC GPIO State

Register an IPMI command handler - NetFn: 0x38 Cmd: 0x03.
Send command through IPMB to get BIC GPIO state.
Add Meta IANA definition for future utilization.

Limitation:
1. Could only get the state of BIC GPIOs which are configured as GPIO
2. Couldn't get all BIC GPIO states

Test Case:
Call IPMI OEM get BIC GPIO state

Signed-off-by: Bonnie Lo <Bonnie_Lo@wiwynn.com>
Change-Id: Idda8d4c532b2971c14662e7b34ea101cf584fa22
diff --git a/include/biccommands.hpp b/include/biccommands.hpp
index 5493304..e8742d1 100644
--- a/include/biccommands.hpp
+++ b/include/biccommands.hpp
@@ -1,9 +1,10 @@
 
-// Command for getting device id
-constexpr uint8_t cmdOemBicInfo = 0x01;
-
-// Command for getting post code
-constexpr uint8_t cmdOemSendPostBufferToBMC = 0x08;
+enum class fb_bic_cmds : uint8_t
+{
+    CMD_OEM_BIC_INFO = 0x1,
+    CMD_OEM_GET_BIC_GPIO_STATE = 0x3,
+    CMD_OEM_SEND_POST_BUFFER_TO_BMC = 0x8,
+};
 
 const char* dbusObj = "/xyz/openbmc_project/state/boot/raw";
 
diff --git a/include/commandutils.hpp b/include/commandutils.hpp
index e318f13..d51c0e8 100644
--- a/include/commandutils.hpp
+++ b/include/commandutils.hpp
@@ -22,6 +22,10 @@
 
 static constexpr bool debug = false;
 
+using IanaType = std::array<uint8_t, 3>;
+
+static constexpr IanaType iana = {0x15, 0xA0, 0x0}; // Meta's IANA
+
 static void instances(std::string s, std::vector<std::string>& host)
 {
     size_t pos = 0;
diff --git a/src/biccommands.cpp b/src/biccommands.cpp
index 0813593..5212452 100644
--- a/src/biccommands.cpp
+++ b/src/biccommands.cpp
@@ -37,15 +37,18 @@
 
 extern message::Response::ptr executeIpmiCommand(message::Request::ptr);
 
+int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&,
+               std::vector<uint8_t>&);
+
 //----------------------------------------------------------------------
 // ipmiOemBicHandler (IPMI/Section - ) (CMD_OEM_BIC_INFO)
 // This Function will handle BIC request for netfn=0x38 and cmd=1
 // send the response back to the sender.
 //----------------------------------------------------------------------
 
-ipmi::RspType<std::array<uint8_t, 3>, uint8_t, uint2_t, uint6_t, uint8_t,
-              uint8_t, ipmi::message::Payload>
-    ipmiOemBicHandler(ipmi::Context::ptr ctx, std::array<uint8_t, 3> iana,
+ipmi::RspType<IanaType, uint8_t, uint2_t, uint6_t, uint8_t, uint8_t,
+              ipmi::message::Payload>
+    ipmiOemBicHandler(ipmi::Context::ptr ctx, IanaType reqIana,
                       uint8_t interface, uint2_t lun, uint6_t netFnReq,
                       uint8_t cmdReq, SecureBuffer data)
 {
@@ -63,7 +66,7 @@
     res = ipmi::executeIpmiCommand(req);
 
     // sending the response with headers and payload
-    return ipmi::responseSuccess(iana, interface, lun, ++netFnReq, cmdReq,
+    return ipmi::responseSuccess(reqIana, interface, lun, ++netFnReq, cmdReq,
                                  res->cc, res->payload);
 }
 
@@ -73,9 +76,10 @@
 // netfn=0x38 and cmd=0x08 send the response back to the sender.
 //----------------------------------------------------------------------
 
-ipmi::RspType<std::array<uint8_t, 3>>
-    ipmiOemPostCodeHandler(ipmi::Context::ptr ctx, std::array<uint8_t, 3> iana,
-                           uint8_t dataLen, std::vector<uint8_t> data)
+ipmi::RspType<IanaType> ipmiOemPostCodeHandler(ipmi::Context::ptr ctx,
+                                               IanaType reqIana,
+                                               uint8_t dataLen,
+                                               std::vector<uint8_t> data)
 {
     // creating bus connection
     auto conn = getSdBus();
@@ -113,7 +117,42 @@
         }
     }
 
-    return ipmi::responseSuccess(iana);
+    return ipmi::responseSuccess(reqIana);
+}
+
+//----------------------------------------------------------------------
+// ipmiOemGetBicGpioState (CMD_OEM_GET_BIC_GPIO_STATE)
+// This Function will handle BIC GPIO stats for
+// netfn=0x38 and cmd=0x03 send the response back to the sender.
+//----------------------------------------------------------------------
+
+ipmi::RspType<IanaType, std::vector<uint8_t>>
+    ipmiOemGetBicGpioState(ipmi::Context::ptr ctx, std::vector<uint8_t> reqIana)
+{
+    std::vector<uint8_t> respData;
+
+    if (std::equal(reqIana.begin(), reqIana.end(), iana.begin()) == false)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "Invalid IANA number");
+        return ipmi::responseInvalidFieldRequest();
+    }
+
+    uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
+
+    if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqIana, respData))
+    {
+        return ipmi::responseUnspecifiedError();
+    }
+
+    std::vector<uint8_t> gpioState;
+    IanaType respIana;
+
+    auto r =
+        std::ranges::copy_n(respData.begin(), iana.size(), respIana.begin()).in;
+    std::copy(r, respData.end(), std::back_inserter(gpioState));
+
+    return ipmi::responseSuccess(respIana, gpioState);
 }
 
 [[maybe_unused]] static void registerBICFunctions(void)
@@ -123,11 +162,16 @@
         "Registering BIC commands");
 
     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
-                          cmdOemBicInfo, ipmi::Privilege::User,
-                          ipmiOemBicHandler);
-    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
-                          cmdOemSendPostBufferToBMC, ipmi::Privilege::User,
-                          ipmiOemPostCodeHandler);
+                          static_cast<Cmd>(fb_bic_cmds::CMD_OEM_BIC_INFO),
+                          ipmi::Privilege::User, ipmiOemBicHandler);
+    ipmi::registerHandler(
+        ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
+        static_cast<Cmd>(fb_bic_cmds::CMD_OEM_SEND_POST_BUFFER_TO_BMC),
+        ipmi::Privilege::User, ipmiOemPostCodeHandler);
+    ipmi::registerHandler(
+        ipmi::prioOemBase, ipmi::netFnOemFive,
+        static_cast<Cmd>(fb_bic_cmds::CMD_OEM_GET_BIC_GPIO_STATE),
+        ipmi::Privilege::User, ipmiOemGetBicGpioState);
     return;
 }