host-ipmid: sol: Add get/set sol conf params command

Move set/get sol config parameter command from net-ipmid to
host-ipmid, these commands could be set by other interface,
not Lan only.

Notice:
In host-ipmid, will get/set the dbus properties only, need sol
manager register the signal to update sol manager when properties
changed.

When we use ipmitool command with channel num parameter, if you do not
specify the channel num, the default channel num always be 0xE in
command, and, we always treat channel 0xE channel is current channel.
So, if you use a command "ipmitool sol info" in console, because
this is not a lan channel, it will return "Error requesting SOL
parameter 'Set In Progress (0)': Invalid data field in request".

In net-ipmid use current channel only, ignored the channel number in
parameter, always return the current lan channel.

Tested:
1. Check sol conf.
ipmitool sol info 1
Set in progress                 : set-complete
Enabled                         : true
Force Encryption                : false
Force Authentication            : false
Privilege Level                 : ADMINISTRATOR
Character Accumulate Level (ms) : 500
Character Send Threshold        : 1
Retry Count                     : 7
Retry Interval (ms)             : 1000
Volatile Bit Rate (kbps)        : IPMI-Over-Serial-Setting
Non-Volatile Bit Rate (kbps)    : IPMI-Over-Serial-Setting
Payload Channel                 : 1 (0x01)
Payload Port                    : 623

2. Sel sol conf with a non-lan channel, in my env, lan channel num is 1
ipmitool sol set enabled false 1
ipmitool sol set force-encryption true 1
ipmitool sol set force-authentication true 1
ipmitool sol set privilege-level user 1
ipmitool sol set character-accumulate-level 200 1
ipmitool sol set character-send-threshold 200 1
ipmitool sol set retry-count 5 1
ipmitool sol set retry-interval 20 1

or

ipmitool -I lanplus -H x -U x -P x sol set enabled false
ipmitool -I lanplus -H x -U x -P x sol set force-encryption true
ipmitool -I lanplus -H x -U x -P x sol set force-authentication true
ipmitool -I lanplus -H x -U x -P x sol set privilege-level user
ipmitool -I lanplus -H x -U x -P x sol set character-accumulate-level 200
ipmitool -I lanplus -H x -U x -P x sol set character-send-threshold 200
ipmitool -I lanplus -H x -U x -P x sol set retry-count 5
ipmitool -I lanplus -H x -U x -P x sol set retry-interval 20

3. Check sol conf, same as set.
ipmitool sol info 1
Set in progress                 : set-complete
Enabled                         : false
Force Encryption                : true
Force Authentication            : true
Privilege Level                 : USER
Character Accumulate Level (ms) : 1000
Character Send Threshold        : 200
Retry Count                     : 5
Retry Interval (ms)             : 200
Volatile Bit Rate (kbps)        : IPMI-Over-Serial-Setting
Non-Volatile Bit Rate (kbps)    : IPMI-Over-Serial-Setting
Payload Channel                 : 1 (0x01)
Payload Port                    : 623

Change-Id: I1ac65881c41ad644ffc19720c0b00988eaca03e4
Signed-off-by: Jian Zhang <zhangjian.3032@bytedance.com>
diff --git a/transporthandler.cpp b/transporthandler.cpp
index f7585a4..056c3f5 100644
--- a/transporthandler.cpp
+++ b/transporthandler.cpp
@@ -1529,6 +1529,327 @@
     return response(ccParamNotSupported);
 }
 
+constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL";
+constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/";
+constexpr const uint16_t solDefaultPort = 623;
+
+RspType<> setSolConfParams(Context::ptr ctx, uint4_t channelBits,
+                           uint4_t reserved, uint8_t parameter,
+                           message::Payload& req)
+{
+    const uint8_t channel = convertCurrentChannelNum(
+        static_cast<uint8_t>(channelBits), ctx->channel);
+
+    if (!isValidChannel(channel))
+    {
+        log<level::ERR>("Set Sol Config - Invalid channel in request");
+        return responseInvalidFieldRequest();
+    }
+
+    std::string solService{};
+    std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel);
+
+    if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService))
+    {
+        log<level::ERR>("Set Sol Config - Invalid solInterface",
+                        entry("SERVICE=%s", solService.c_str()),
+                        entry("OBJPATH=%s", solPathWitheEthName.c_str()),
+                        entry("INTERFACE=%s", solInterface));
+        return responseInvalidFieldRequest();
+    }
+
+    switch (static_cast<SolConfParam>(parameter))
+    {
+        case SolConfParam::Progress:
+        {
+            uint8_t progress;
+            if (req.unpack(progress) != 0 || !req.fullyUnpacked())
+            {
+                return responseReqDataLenInvalid();
+            }
+
+            if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "Progress", progress))
+            {
+                return responseUnspecifiedError();
+            }
+            break;
+        }
+        case SolConfParam::Enable:
+        {
+            bool enable;
+            uint7_t reserved2;
+
+            if (req.unpack(enable, reserved2) != 0 || !req.fullyUnpacked())
+            {
+                return responseReqDataLenInvalid();
+            }
+
+            if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "Enable", enable))
+            {
+                return responseUnspecifiedError();
+            }
+            break;
+        }
+        case SolConfParam::Authentication:
+        {
+            uint4_t privilegeBits{};
+            uint2_t reserved2{};
+            bool forceAuth = false;
+            bool forceEncrypt = false;
+
+            if (req.unpack(privilegeBits, reserved2, forceAuth, forceEncrypt) !=
+                    0 ||
+                !req.fullyUnpacked())
+            {
+                return responseReqDataLenInvalid();
+            }
+
+            uint8_t privilege = static_cast<uint8_t>(privilegeBits);
+            if (privilege < static_cast<uint8_t>(Privilege::None) ||
+                privilege > static_cast<uint8_t>(Privilege::Oem))
+            {
+                return ipmi::responseInvalidFieldRequest();
+            }
+
+            if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "Privilege", privilege))
+            {
+                return responseUnspecifiedError();
+            }
+
+            if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "ForceEncryption",
+                                      forceEncrypt))
+            {
+                return responseUnspecifiedError();
+            }
+
+            if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "ForceAuthentication",
+                                      forceAuth))
+            {
+                return responseUnspecifiedError();
+            }
+            break;
+        }
+        case SolConfParam::Accumulate:
+        {
+            uint8_t interval;
+            uint8_t threshold;
+            if (req.unpack(interval, threshold) != 0 || !req.fullyUnpacked())
+            {
+                return responseReqDataLenInvalid();
+            }
+
+            if (threshold == 0)
+            {
+                return responseInvalidFieldRequest();
+            }
+
+            if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "AccumulateIntervalMS",
+                                      interval))
+            {
+                return responseUnspecifiedError();
+            }
+
+            if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "Threshold", threshold))
+            {
+                return responseUnspecifiedError();
+            }
+            break;
+        }
+        case SolConfParam::Retry:
+        {
+            uint3_t countBits;
+            uint5_t reserved2;
+            uint8_t interval;
+
+            if (req.unpack(countBits, reserved2, interval) != 0 ||
+                !req.fullyUnpacked())
+            {
+                return responseReqDataLenInvalid();
+            }
+
+            uint8_t count = static_cast<uint8_t>(countBits);
+            if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "RetryCount", count))
+            {
+                return responseUnspecifiedError();
+            }
+
+            if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "RetryIntervalMS",
+                                      interval))
+            {
+                return responseUnspecifiedError();
+            }
+            break;
+        }
+        case SolConfParam::Port:
+        {
+            return response(ipmiCCWriteReadParameter);
+        }
+        case SolConfParam::NonVbitrate:
+        case SolConfParam::Vbitrate:
+        case SolConfParam::Channel:
+        default:
+            return response(ipmiCCParamNotSupported);
+    }
+    return responseSuccess();
+}
+
+RspType<message::Payload> getSolConfParams(Context::ptr ctx,
+                                           uint4_t channelBits,
+                                           uint3_t reserved, bool revOnly,
+                                           uint8_t parameter, uint8_t set,
+                                           uint8_t block)
+{
+    message::Payload ret;
+    constexpr uint8_t current_revision = 0x11;
+    ret.pack(current_revision);
+    if (revOnly)
+    {
+        return responseSuccess(std::move(ret));
+    }
+
+    const uint8_t channel = convertCurrentChannelNum(
+        static_cast<uint8_t>(channelBits), ctx->channel);
+
+    if (!isValidChannel(channel))
+    {
+        log<level::ERR>("Get Sol Config - Invalid channel in request");
+        return responseInvalidFieldRequest();
+    }
+
+    std::string solService{};
+    std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel);
+
+    if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService))
+    {
+        log<level::ERR>("Set Sol Config - Invalid solInterface",
+                        entry("SERVICE=%s", solService.c_str()),
+                        entry("OBJPATH=%s", solPathWitheEthName.c_str()),
+                        entry("INTERFACE=%s", solInterface));
+        return responseInvalidFieldRequest();
+    }
+
+    switch (static_cast<SolConfParam>(parameter))
+    {
+        case SolConfParam::Progress:
+        {
+            uint8_t progress;
+            if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "Progress", progress))
+            {
+                return responseUnspecifiedError();
+            }
+            ret.pack(progress);
+            return responseSuccess(std::move(ret));
+        }
+        case SolConfParam::Enable:
+        {
+            bool enable{};
+            if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "Enable", enable))
+            {
+                return responseUnspecifiedError();
+            }
+            ret.pack(enable, uint7_t{});
+            return responseSuccess(std::move(ret));
+        }
+        case SolConfParam::Authentication:
+        {
+            // 4bits, cast when pack
+            uint8_t privilege;
+            bool forceAuth = false;
+            bool forceEncrypt = false;
+
+            if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "Privilege", privilege))
+            {
+                return responseUnspecifiedError();
+            }
+
+            if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "ForceAuthentication",
+                                      forceAuth))
+            {
+                return responseUnspecifiedError();
+            }
+
+            if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "ForceEncryption",
+                                      forceEncrypt))
+            {
+                return responseUnspecifiedError();
+            }
+            ret.pack(uint4_t{privilege}, uint2_t{}, forceAuth, forceEncrypt);
+            return responseSuccess(std::move(ret));
+        }
+        case SolConfParam::Accumulate:
+        {
+            uint8_t interval{}, threshold{};
+
+            if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "AccumulateIntervalMS",
+                                      interval))
+            {
+                return responseUnspecifiedError();
+            }
+
+            if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "Threshold", threshold))
+            {
+                return responseUnspecifiedError();
+            }
+            ret.pack(interval, threshold);
+            return responseSuccess(std::move(ret));
+        }
+        case SolConfParam::Retry:
+        {
+            // 3bits, cast when cast
+            uint8_t count{};
+            uint8_t interval{};
+
+            if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "RetryCount", count))
+            {
+                return responseUnspecifiedError();
+            }
+
+            if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
+                                      solInterface, "RetryIntervalMS",
+                                      interval))
+            {
+                return responseUnspecifiedError();
+            }
+            ret.pack(uint3_t{count}, uint5_t{}, interval);
+            return responseSuccess(std::move(ret));
+        }
+        case SolConfParam::Port:
+        {
+            auto port = solDefaultPort;
+            ret.pack(static_cast<uint16_t>(port));
+            return responseSuccess(std::move(ret));
+        }
+        case SolConfParam::Channel:
+        {
+            ret.pack(channel);
+            return responseSuccess(std::move(ret));
+        }
+        case SolConfParam::NonVbitrate:
+        case SolConfParam::Vbitrate:
+        default:
+            return response(ipmiCCParamNotSupported);
+    }
+
+    return response(ccParamNotSupported);
+}
+
 } // namespace transport
 } // namespace ipmi
 
@@ -1542,4 +1863,12 @@
     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
                           ipmi::transport::cmdGetLanConfigParameters,
                           ipmi::Privilege::Operator, ipmi::transport::getLan);
+    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
+                          ipmi::transport::cmdSetSolConfigParameters,
+                          ipmi::Privilege::Admin,
+                          ipmi::transport::setSolConfParams);
+    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
+                          ipmi::transport::cmdGetSolConfigParameters,
+                          ipmi::Privilege::User,
+                          ipmi::transport::getSolConfParams);
 }
diff --git a/transporthandler.hpp b/transporthandler.hpp
index b62de83..6c58dc5 100644
--- a/transporthandler.hpp
+++ b/transporthandler.hpp
@@ -678,5 +678,25 @@
     }
 }
 
+/** @enum SolConfParam
+ *
+ *  using for Set/Get SOL configuration parameters command.
+ */
+enum class SolConfParam : uint8_t
+{
+    Progress,       //!< Set In Progress.
+    Enable,         //!< SOL Enable.
+    Authentication, //!< SOL Authentication.
+    Accumulate,     //!< Character Accumulate Interval & Send Threshold.
+    Retry,          //!< SOL Retry.
+    NonVbitrate,    //!< SOL non-volatile bit rate.
+    Vbitrate,       //!< SOL volatile bit rate.
+    Channel,        //!< SOL payload channel.
+    Port,           //!< SOL payload port.
+};
+
+constexpr uint8_t ipmiCCParamNotSupported = 0x80;
+constexpr uint8_t ipmiCCWriteReadParameter = 0x82;
+
 } // namespace transport
 } // namespace ipmi