summaryrefslogtreecommitdiffstats
path: root/transporthandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'transporthandler.cpp')
-rw-r--r--transporthandler.cpp325
1 files changed, 325 insertions, 0 deletions
diff --git a/transporthandler.cpp b/transporthandler.cpp
index f4326c1..bbc6ae5 100644
--- a/transporthandler.cpp
+++ b/transporthandler.cpp
@@ -22,7 +22,19 @@
#include <mapper.h>
#endif
+/** @struct SetChannelAccessRequest
+ *
+ * IPMI payload for Set Channel access command request.
+ */
+struct SetChannelAccessRequest
+{
+ uint8_t channelNumber; //!< Channel number.
+ uint8_t setting; //!< The setting values.
+ uint8_t privilegeLevelLimit; //!< The Privilege Level Limit
+} __attribute__((packed));
+
const int SIZE_MAC = 18; //xx:xx:xx:xx:xx:xx
+constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig;
@@ -620,6 +632,319 @@ ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn,
return rc;
}
+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;
+
+ if (*data_len < sizeof(SetChannelAccessRequest))
+ {
+ return IPMI_CC_INVALID;
+ }
+
+ auto requestData = reinterpret_cast<const SetChannelAccessRequest*>
+ (request);
+ int channel = requestData->channelNumber & CHANNEL_MASK;
+
+ auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
+ if (ethdevice.empty())
+ {
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+ auto ethIp = ethdevice + "/" + ipmi::network::IP_TYPE;
+ auto channelConf = getChannelConfig(channel);
+
+ // 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", channelConf->netmask.c_str()),
+ entry("ADDRESS=%s", channelConf->ipaddr.c_str()),
+ entry("GATEWAY=%s", channelConf->gateway.c_str()),
+ entry("VLAN=%d", channelConf->vlanID),
+ entry("IPSRC=%d", channelConf->ipsrc));
+ if (channelConf->vlanID != ipmi::network::VLAN_ID_MASK)
+ {
+ //get the first twelve bits which is vlan id
+ //not interested in rest of the bits.
+ channelConf->vlanID = le32toh(channelConf->vlanID);
+ vlanID = channelConf->vlanID & ipmi::network::VLAN_ID_MASK;
+ }
+
+ // if the asked ip src is DHCP then not interested in
+ // any given data except vlan.
+ if (channelConf->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,
+ ethIp);
+
+ // 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;
+ channelConf->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,
+ ethdevice);
+
+ 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>();
+
+ // if ip address source is not given then get the ip source mode
+ // from the system so that it can be applied later.
+ if (channelConf->ipsrc == ipmi::network::IPOrigin::UNSPECIFIED)
+ {
+ channelConf->ipsrc = (enableDHCP) ?
+ ipmi::network::IPOrigin::DHCP :
+ ipmi::network::IPOrigin::STATIC;
+ }
+
+ // 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 ((!channelConf->ipaddr.empty() &&
+ !channelConf->netmask.empty() &&
+ !channelConf->gateway.empty()) ||
+ (enableDHCP)) // configured system interface mode = DHCP
+ {
+ //convert mask into prefix
+ ipaddress = channelConf->ipaddr;
+ prefix = ipmi::network::toPrefix(AF_INET, channelConf->netmask);
+ gateway = channelConf->gateway;
+ }
+ 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 = channelConf->ipaddr.empty() ?
+ properties["Address"].get<std::string>() :
+ channelConf->ipaddr;
+
+ prefix = channelConf->netmask.empty() ?
+ properties["PrefixLength"].get<uint8_t>() :
+ ipmi::network::toPrefix(AF_INET,
+ channelConf->netmask);
+ }
+ catch (InternalFailure& e)
+ {
+ log<level::INFO>("Failed to get IP object which matches",
+ entry("INTERFACE=%s", ipmi::network::IP_INTERFACE),
+ entry("MATCH=%s", ethIp));
+ }
+
+ auto systemProperties = ipmi::getAllDbusProperties(
+ bus,
+ systemObject.second,
+ systemObject.first,
+ ipmi::network::SYSTEMCONFIG_INTERFACE);
+
+ gateway = channelConf->gateway.empty() ?
+ systemProperties["DefaultGateway"].get<std::string>() :
+ channelConf->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,
+ ethdevice);
+
+ // 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,
+ ethIp);
+
+ if (vlanID)
+ {
+ ipmi::network::createVLAN(bus,
+ ipmi::network::SERVICE,
+ ipmi::network::ROOT,
+ ethdevice,
+ vlanID);
+
+ auto networkInterfaceObject = ipmi::getDbusObject(
+ bus,
+ ipmi::network::VLAN_INTERFACE,
+ ipmi::network::ROOT);
+
+ networkInterfacePath = networkInterfaceObject.first;
+ }
+
+ if (channelConf->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", channelConf->ipsrc));
+
+ commit<InternalFailure>();
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ }
+
+ channelConf->clear();
+ return rc;
+}
+
void register_netfn_transport_functions()
{
// <Wildcard Command>
OpenPOWER on IntegriCloud