summaryrefslogtreecommitdiffstats
path: root/app/channel.cpp
diff options
context:
space:
mode:
authorPatrick Venture <venture@google.com>2017-10-26 11:11:14 -0700
committerPatrick Venture <venture@google.com>2017-10-26 14:01:40 -0700
commit5794fcf6f311068ef88a0cb2bd838953f08c3223 (patch)
tree5cfb6f5eadef317048291a966aac19758f03d6fa /app/channel.cpp
parent5e6ac715611ab118d243318ea44523cc67de77c4 (diff)
downloadphosphor-host-ipmid-5794fcf6f311068ef88a0cb2bd838953f08c3223.tar.gz
phosphor-host-ipmid-5794fcf6f311068ef88a0cb2bd838953f08c3223.zip
apphandler: channel: split out commands
I split out the channel commands into their own subordinate file from the apphandler.cpp. There are three commands in apphandler for the channel information. There are other commands in the transporthandler that correlate. Moving this is step one in a larger task to enable multiple channels. Change-Id: I2e434a1da942325fc420079415edb39622f4e346 Signed-off-by: Patrick Venture <venture@google.com>
Diffstat (limited to 'app/channel.cpp')
-rw-r--r--app/channel.cpp428
1 files changed, 428 insertions, 0 deletions
diff --git a/app/channel.cpp b/app/channel.cpp
new file mode 100644
index 0000000..72f1571
--- /dev/null
+++ b/app/channel.cpp
@@ -0,0 +1,428 @@
+#include "channel.hpp"
+#include "types.hpp"
+#include "transporthandler.hpp"
+#include "utils.hpp"
+
+#include <string>
+#include <arpa/inet.h>
+
+#include <phosphor-logging/log.hpp>
+#include <phosphor-logging/elog-errors.hpp>
+#include "xyz/openbmc_project/Common/error.hpp"
+
+extern struct ChannelConfig_t channelConfig;
+
+constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
+
+using namespace phosphor::logging;
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+
+/** @struct GetChannelAccessRequest
+ *
+ * IPMI payload for Get Channel access command request.
+ */
+struct GetChannelAccessRequest
+{
+ uint8_t channelNumber; //!< Channel number.
+ uint8_t volatileSetting; //!< Get non-volatile or the volatile setting.
+} __attribute__((packed));
+
+/** @struct GetChannelAccessResponse
+ *
+ * IPMI payload for Get Channel access command response.
+ */
+struct GetChannelAccessResponse
+{
+ uint8_t settings; //!< Channel settings.
+ uint8_t privilegeLimit; //!< Channel privilege level limit.
+} __attribute__((packed));
+
+ipmi_ret_t ipmi_set_channel_access(ipmi_netfn_t netfn,
+ ipmi_cmd_t cmd,
+ ipmi_request_t request,
+ ipmi_response_t response,
+ ipmi_data_len_t data_len,
+ ipmi_context_t context)
+{
+ ipmi_ret_t rc = IPMI_CC_OK;
+
+ std::string ipaddress;
+ std::string gateway;
+ uint8_t prefix {};
+ uint32_t vlanID {};
+ std::string networkInterfacePath;
+ ipmi::DbusObjectInfo ipObject;
+ ipmi::DbusObjectInfo systemObject;
+
+ // Todo: parse the request data if needed.
+ // Using Set Channel cmd to apply changes of Set Lan Cmd.
+ try
+ {
+ sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
+
+ log<level::INFO>("Network data from Cache",
+ entry("PREFIX=%s", channelConfig.netmask.c_str()),
+ entry("ADDRESS=%s", channelConfig.ipaddr.c_str()),
+ entry("GATEWAY=%s", channelConfig.gateway.c_str()),
+ entry("VLAN=%d", channelConfig.vlanID),
+ entry("IPSRC=%d", channelConfig.ipsrc));
+
+ if (channelConfig.vlanID != ipmi::network::VLAN_ID_MASK)
+ {
+ //get the first twelve bits which is vlan id
+ //not interested in rest of the bits.
+ channelConfig.vlanID = le32toh(channelConfig.vlanID);
+ vlanID = channelConfig.vlanID & ipmi::network::VLAN_ID_MASK;
+ }
+
+ // if the asked ip src is DHCP then not interested in
+ // any given data except vlan.
+ if (channelConfig.ipsrc != ipmi::network::IPOrigin::DHCP)
+ {
+ // always get the system object
+ systemObject = ipmi::getDbusObject(
+ bus,
+ ipmi::network::SYSTEMCONFIG_INTERFACE,
+ ipmi::network::ROOT);
+
+ // the below code is to determine the mode of the interface
+ // as the handling is same, if the system is configured with
+ // DHCP or user has given all the data.
+ try
+ {
+ ipmi::ObjectTree ancestorMap;
+
+ ipmi::InterfaceList interfaces {
+ ipmi::network::ETHERNET_INTERFACE };
+
+ // if the system is having ip object,then
+ // get the IP object.
+ ipObject = ipmi::getDbusObject(bus,
+ ipmi::network::IP_INTERFACE,
+ ipmi::network::ROOT,
+ ipmi::network::IP_TYPE);
+
+ // Get the parent interface of the IP object.
+ try
+ {
+ ancestorMap = ipmi::getAllAncestors(bus,
+ ipObject.first,
+ std::move(interfaces));
+ }
+ catch (InternalFailure& e)
+ {
+ // if unable to get the parent interface
+ // then commit the error and return.
+ log<level::ERR>("Unable to get the parent interface",
+ entry("PATH=%s", ipObject.first.c_str()),
+ entry("INTERFACE=%s",
+ ipmi::network::ETHERNET_INTERFACE));
+ commit<InternalFailure>();
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ channelConfig.clear();
+ return rc;
+ }
+
+ networkInterfacePath = ancestorMap.begin()->first;
+ }
+ catch (InternalFailure& e)
+ {
+ // TODO Currently IPMI supports single interface,need to handle
+ // Multiple interface through
+ // https://github.com/openbmc/openbmc/issues/2138
+
+ // if there is no ip configured on the system,then
+ // get the network interface object.
+ auto networkInterfaceObject = ipmi::getDbusObject(
+ bus,
+ ipmi::network::ETHERNET_INTERFACE,
+ ipmi::network::ROOT,
+ ipmi::network::INTERFACE);
+
+ networkInterfacePath = std::move(networkInterfaceObject.first);
+ }
+
+ // get the configured mode on the system.
+ auto enableDHCP = ipmi::getDbusProperty(
+ bus,
+ ipmi::network::SERVICE,
+ networkInterfacePath,
+ ipmi::network::ETHERNET_INTERFACE,
+ "DHCPEnabled").get<bool>();
+
+ // check whether user has given all the data
+ // or the configured system interface is dhcp enabled,
+ // in both of the cases get the values from the cache.
+ if ((!channelConfig.ipaddr.empty() &&
+ !channelConfig.netmask.empty() &&
+ !channelConfig.gateway.empty()) ||
+ (enableDHCP)) // configured system interface mode = DHCP
+ {
+ //convert mask into prefix
+ ipaddress = channelConfig.ipaddr;
+ prefix = ipmi::network::toPrefix(AF_INET, channelConfig.netmask);
+ gateway = channelConfig.gateway;
+ if (channelConfig.vlanID != ipmi::network::VLAN_ID_MASK)
+ {
+ //get the first twelve bits which is vlan id
+ //not interested in rest of the bits.
+ channelConfig.vlanID = le32toh(channelConfig.vlanID);
+ vlanID = channelConfig.vlanID & ipmi::network::VLAN_ID_MASK;
+ }
+ else
+ {
+ vlanID = ipmi::network::getVLAN(networkInterfacePath);
+ }
+
+ }
+ else // asked ip src = static and configured system src = static
+ // or partially given data.
+ {
+ // We have partial filled cache so get the remaining
+ // info from the system.
+
+ // Get the network data from the system as user has
+ // not given all the data then use the data fetched from the
+ // system but it is implementation dependent,IPMI spec doesn't
+ // force it.
+
+ // if system is not having any ip object don't throw error,
+ try
+ {
+ auto properties = ipmi::getAllDbusProperties(
+ bus,
+ ipObject.second,
+ ipObject.first,
+ ipmi::network::IP_INTERFACE);
+
+ ipaddress = channelConfig.ipaddr.empty() ?
+ ipmi::getIPAddress(bus,
+ ipmi::network::IP_INTERFACE,
+ ipmi::network::ROOT,
+ ipmi::network::IP_TYPE) :
+ channelConfig.ipaddr;
+
+ prefix = channelConfig.netmask.empty() ?
+ properties["PrefixLength"].get<uint8_t>() :
+ ipmi::network::toPrefix(AF_INET,
+ channelConfig.netmask);
+
+ }
+ catch (InternalFailure& e)
+ {
+ log<level::INFO>("Failed to get IP object which matches",
+ entry("INTERFACE=%s", ipmi::network::IP_INTERFACE),
+ entry("MATCH=%s", ipmi::network::IP_TYPE));
+ }
+
+ auto systemProperties = ipmi::getAllDbusProperties(
+ bus,
+ systemObject.second,
+ systemObject.first,
+ ipmi::network::SYSTEMCONFIG_INTERFACE);
+
+ gateway = channelConfig.gateway.empty() ?
+ systemProperties["DefaultGateway"].get<std::string>() :
+ channelConfig.gateway;
+
+ }
+ }
+
+ // Currently network manager doesn't support purging of all the
+ // ip addresses and the vlan interfaces from the parent interface,
+ // TODO once the support is there, will make the change here.
+ // https://github.com/openbmc/openbmc/issues/2141.
+
+ // TODO Currently IPMI supports single interface,need to handle
+ // Multiple interface through
+ // https://github.com/openbmc/openbmc/issues/2138
+
+ // instead of deleting all the vlan interfaces and
+ // all the ipv4 address,we will call reset method.
+ //delete all the vlan interfaces
+
+ ipmi::deleteAllDbusObjects(bus,
+ ipmi::network::ROOT,
+ ipmi::network::VLAN_INTERFACE);
+
+ // set the interface mode to static
+ auto networkInterfaceObject = ipmi::getDbusObject(
+ bus,
+ ipmi::network::ETHERNET_INTERFACE,
+ ipmi::network::ROOT,
+ ipmi::network::INTERFACE);
+
+ // setting the physical interface mode to static.
+ ipmi::setDbusProperty(bus,
+ ipmi::network::SERVICE,
+ networkInterfaceObject.first,
+ ipmi::network::ETHERNET_INTERFACE,
+ "DHCPEnabled",
+ false);
+
+ networkInterfacePath = networkInterfaceObject.first;
+
+ //delete all the ipv4 addresses
+ ipmi::deleteAllDbusObjects(bus,
+ ipmi::network::ROOT,
+ ipmi::network::IP_INTERFACE,
+ ipmi::network::IP_TYPE);
+
+ if (vlanID)
+ {
+ ipmi::network::createVLAN(bus,
+ ipmi::network::SERVICE,
+ ipmi::network::ROOT,
+ ipmi::network::INTERFACE,
+ vlanID);
+
+ auto networkInterfaceObject = ipmi::getDbusObject(
+ bus,
+ ipmi::network::VLAN_INTERFACE,
+ ipmi::network::ROOT);
+
+ networkInterfacePath = networkInterfaceObject.first;
+ }
+
+ if (channelConfig.ipsrc == ipmi::network::IPOrigin::DHCP)
+ {
+ ipmi::setDbusProperty(bus,
+ ipmi::network::SERVICE,
+ networkInterfacePath,
+ ipmi::network::ETHERNET_INTERFACE,
+ "DHCPEnabled",
+ true);
+ }
+ else
+ {
+ //change the mode to static
+ ipmi::setDbusProperty(bus,
+ ipmi::network::SERVICE,
+ networkInterfacePath,
+ ipmi::network::ETHERNET_INTERFACE,
+ "DHCPEnabled",
+ false);
+
+ if (!ipaddress.empty())
+ {
+ ipmi::network::createIP(bus,
+ ipmi::network::SERVICE,
+ networkInterfacePath,
+ ipv4Protocol,
+ ipaddress,
+ prefix);
+ }
+
+ if (!gateway.empty())
+ {
+ ipmi::setDbusProperty(bus,
+ systemObject.second,
+ systemObject.first,
+ ipmi::network::SYSTEMCONFIG_INTERFACE,
+ "DefaultGateway",
+ std::string(gateway));
+ }
+ }
+
+ }
+ catch (InternalFailure& e)
+ {
+ log<level::ERR>("Failed to set network data",
+ entry("PREFIX=%d", prefix),
+ entry("ADDRESS=%s", ipaddress.c_str()),
+ entry("GATEWAY=%s", gateway.c_str()),
+ entry("VLANID=%d", vlanID),
+ entry("IPSRC=%d", channelConfig.ipsrc));
+
+ commit<InternalFailure>();
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ }
+
+ channelConfig.clear();
+ return rc;
+}
+
+ipmi_ret_t ipmi_get_channel_access(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ auto requestData = reinterpret_cast<const GetChannelAccessRequest*>
+ (request);
+ std::vector<uint8_t> outPayload(sizeof(GetChannelAccessResponse));
+ auto responseData = reinterpret_cast<GetChannelAccessResponse*>
+ (outPayload.data());
+
+ // Channel 1 is arbitrarily assigned to ETH0 channel
+ constexpr auto channelOne = 0x01;
+
+ /*
+ * The value Eh is used as a way to identify the current channel that
+ * the command is being received from.
+ */
+ constexpr auto channelE = 0x0E;
+
+ if (requestData->channelNumber != channelOne &&
+ requestData->channelNumber != channelE)
+ {
+ *data_len = 0;
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+
+ /*
+ * [7:6] - reserved
+ * [5] - 1b = Alerting disabled
+ * [4] - 1b = per message authentication disabled
+ * [3] - 0b = User level authentication enabled
+ * [2:0] - 2h = always available
+ */
+ constexpr auto channelSetting = 0x32;
+
+ responseData->settings = channelSetting;
+ //Defaulting the channel privilege to administrator level.
+ responseData->privilegeLimit = PRIVILEGE_ADMIN;
+
+ *data_len = outPayload.size();
+ memcpy(response, outPayload.data(), *data_len);
+
+ return IPMI_CC_OK;
+}
+
+// ATTENTION: This ipmi function is very hardcoded on purpose
+// OpenBMC does not fully support IPMI. This command is useful
+// to have around because it enables testing of interfaces with
+// the IPMI tool.
+#define GET_CHANNEL_INFO_CHANNEL_OFFSET 0
+// IPMI Table 6-2
+#define IPMI_CHANNEL_TYPE_IPMB 1
+// IPMI Table 6-3
+#define IPMI_CHANNEL_MEDIUM_TYPE_OTHER 6
+
+ipmi_ret_t ipmi_app_channel_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ ipmi_ret_t rc = IPMI_CC_OK;
+ uint8_t resp[] = {
+ 1,
+ IPMI_CHANNEL_MEDIUM_TYPE_OTHER,
+ IPMI_CHANNEL_TYPE_IPMB,
+ 1,0x41,0xA7,0x00,0,0};
+ uint8_t *p = (uint8_t*) request;
+
+ printf("IPMI APP GET CHANNEL INFO\n");
+
+ // The supported channels numbers are 1 and 8.
+ // Channel Number E is used as way to identify the current channel
+ // that the command is being is received from.
+ if (*p == 0xe || *p == 1 || *p == 8) {
+
+ *data_len = sizeof(resp);
+ memcpy(response, resp, *data_len);
+
+ } else {
+ rc = IPMI_CC_PARM_OUT_OF_RANGE;
+ *data_len = 0;
+ }
+
+ return rc;
+}
OpenPOWER on IntegriCloud