Override the Platform Event command

Override the Platform Event IPMI command to allow injecting
the hook to convert IPMI events to Redfish messages.

There are two ToDos in this change that are pending support
from other patches:
   1. Getting the incoming channel.
   2. Getting the IPMB requester's slave address.

Until we have these the workarounds in this patch are to use
the EvMRev to determine if the Generator ID byte is in the
request and to hardcode the requester's slave address to 0x2C
for the ME since that is the main IPMB requester we support.

Tested:
Ran the following IPMI commands and checked that the correct
SEL events were logged:
ipmitool raw 0x4 0x2 0x4 0x1 0x6 0x1 0xa4 5 6
ipmitool raw 0x4 0x2 0x81 0x4 0x1 0x6 0x1 0xa4

Change-Id: I7ec31b3e895300ebe4f09407f5f5cabd106bfa22
Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/src/sensorcommands.cpp b/src/sensorcommands.cpp
index 662cd45..9589d64 100644
--- a/src/sensorcommands.cpp
+++ b/src/sensorcommands.cpp
@@ -231,6 +231,68 @@
     return IPMI_CC_INVALID;
 }
 
+ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload &p)
+{
+    uint8_t generatorID = 0;
+    uint8_t evmRev = 0;
+    uint8_t sensorType = 0;
+    uint8_t sensorNum = 0;
+    uint8_t eventType = 0;
+    uint8_t eventData1 = 0;
+    std::optional<uint8_t> eventData2 = 0;
+    std::optional<uint8_t> eventData3 = 0;
+
+    // todo: This check is supposed to be based on the incoming channel.
+    //      e.g. system channel will provide upto 8 bytes including generator
+    //      ID, but ipmb channel will provide only up to 7 bytes without the
+    //      generator ID.
+    // Support for this check is coming in future patches, so for now just base
+    // it on if the first byte is the EvMRev (0x04).
+    if (p.size() && p.data()[0] == 0x04)
+    {
+        p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
+                 eventData2, eventData3);
+        // todo: the generator ID for this channel is supposed to come from the
+        // IPMB requesters slave address. Support for this is coming in future
+        // patches, so for now just assume it is coming from the ME (0x2C).
+        generatorID = 0x2C;
+    }
+    else
+    {
+        p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
+                 eventData1, eventData2, eventData3);
+    }
+    if (!p.fullyUnpacked())
+    {
+        return ipmi::responseReqDataLenInvalid();
+    }
+
+    bool assert = eventType & directionMask ? false : true;
+    std::vector<uint8_t> eventData;
+    eventData.push_back(eventData1);
+    eventData.push_back(eventData2.value_or(0xFF));
+    eventData.push_back(eventData3.value_or(0xFF));
+
+    std::string sensorPath = getPathFromSensorNumber(sensorNum);
+    std::string service =
+        ipmi::getService(dbus, ipmiSELAddInterface, ipmiSELPath);
+    sdbusplus::message::message writeSEL = dbus.new_method_call(
+        service.c_str(), ipmiSELPath, ipmiSELAddInterface, "IpmiSelAdd");
+    writeSEL.append(ipmiSELAddMessage, sensorPath, eventData, assert,
+                    static_cast<uint16_t>(generatorID));
+    try
+    {
+        dbus.call(writeSEL);
+    }
+    catch (sdbusplus::exception_t &e)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
+        return ipmi::responseUnspecifiedError();
+    }
+
+    return ipmi::responseSuccess();
+}
+
 ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
     ipmiSenGetSensorReading(uint8_t sensnum)
 {
@@ -1259,6 +1321,12 @@
             IPMINetfnSensorCmds::ipmiCmdSetSensorReadingAndEventStatus),
         nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
 
+    // <Platform Event>
+    ipmi::registerHandler(
+        ipmi::prioOemBase, ipmi::netFnSensor,
+        static_cast<ipmi::Cmd>(ipmi::sensor_event::cmdPlatformEvent),
+        ipmi::Privilege::Operator, ipmiSenPlatformEvent);
+
     // <Get Sensor Reading>
     ipmi::registerHandler(
         ipmi::prioOemBase, NETFUN_SENSOR,