multiple channel configuration support

Previously, the ipmi daemon only supported eth0 and hard-coded it
to channel 1.  This allows one to map via a configuration.  The
channel number provided is checked against a configuration to retrieve
the ethernet device identifier, e.g. eth0.

Tested: Ran on a quanta-q71l and was able to properly set MAC, IP,
Netmask, Gateway IP, and then verified the data was set for the eth1
via `ip addr show eth1`.

Change-Id: I92f63188297304e9454fd0d6fe32bc6cf84bb181
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/Makefile.am b/Makefile.am
index d4f43db..99808ab 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -49,6 +49,7 @@
 libapphandlerdir = ${libdir}/ipmid-providers
 libapphandler_LTLIBRARIES = libapphandler.la
 libapphandler_la_SOURCES = \
+	net.cpp \
 	app/channel.cpp \
 	app/watchdog.cpp \
 	apphandler.cpp \
diff --git a/app/channel.cpp b/app/channel.cpp
index 91d9987..64cc6e9 100644
--- a/app/channel.cpp
+++ b/app/channel.cpp
@@ -2,6 +2,7 @@
 #include "types.hpp"
 #include "transporthandler.hpp"
 #include "utils.hpp"
+#include "net.hpp"
 
 #include <string>
 #include <arpa/inet.h>
@@ -10,13 +11,22 @@
 #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 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));
+
 /** @struct GetChannelAccessRequest
  *
  *  IPMI payload for Get Channel access command request.
@@ -54,6 +64,22 @@
     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
@@ -61,23 +87,23 @@
         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));
+                         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 (channelConfig.vlanID != ipmi::network::VLAN_ID_MASK)
+        if (channelConf->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;
+            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 (channelConfig.ipsrc != ipmi::network::IPOrigin::DHCP)
+        if (channelConf->ipsrc != ipmi::network::IPOrigin::DHCP)
         {
             // always get the system object
             systemObject = ipmi::getDbusObject(
@@ -97,11 +123,10 @@
 
                 // if the system is having ip object,then
                 // get the IP object.
-                ipObject = ipmi::getIPObject(
-                                bus,
-                                ipmi::network::IP_INTERFACE,
-                                ipmi::network::ROOT,
-                                ipmi::network::IP_TYPE);
+                ipObject = ipmi::getDbusObject(bus,
+                                               ipmi::network::IP_INTERFACE,
+                                               ipmi::network::ROOT,
+                                               ethIp);
 
                 // Get the parent interface of the IP object.
                 try
@@ -120,7 +145,7 @@
                                           ipmi::network::ETHERNET_INTERFACE));
                     commit<InternalFailure>();
                     rc = IPMI_CC_UNSPECIFIED_ERROR;
-                    channelConfig.clear();
+                    channelConf->clear();
                     return rc;
                 }
 
@@ -138,7 +163,7 @@
                         bus,
                         ipmi::network::ETHERNET_INTERFACE,
                         ipmi::network::ROOT,
-                        ipmi::network::INTERFACE);
+                        ethdevice);
 
                 networkInterfacePath = std::move(networkInterfaceObject.first);
             }
@@ -154,21 +179,21 @@
             // 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()) ||
+            if ((!channelConf->ipaddr.empty() &&
+                 !channelConf->netmask.empty() &&
+                 !channelConf->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)
+                ipaddress = channelConf->ipaddr;
+                prefix = ipmi::network::toPrefix(AF_INET, channelConf->netmask);
+                gateway = channelConf->gateway;
+                if (channelConf->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;
+                    channelConf->vlanID = le32toh(channelConf->vlanID);
+                    vlanID = channelConf->vlanID & ipmi::network::VLAN_ID_MASK;
                 }
                 else
                 {
@@ -196,21 +221,20 @@
                             ipObject.first,
                             ipmi::network::IP_INTERFACE);
 
-                    ipaddress = channelConfig.ipaddr.empty() ?
+                    ipaddress = channelConf->ipaddr.empty() ?
                         properties["Address"].get<std::string>() :
-                        channelConfig.ipaddr;
+                        channelConf->ipaddr;
 
-                    prefix = channelConfig.netmask.empty() ?
+                    prefix = channelConf->netmask.empty() ?
                         properties["PrefixLength"].get<uint8_t>() :
                         ipmi::network::toPrefix(AF_INET,
-                                channelConfig.netmask);
-
+                                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", ipmi::network::IP_TYPE));
+                            entry("MATCH=%s", ethIp));
                 }
 
                 auto systemProperties = ipmi::getAllDbusProperties(
@@ -219,10 +243,9 @@
                         systemObject.first,
                         ipmi::network::SYSTEMCONFIG_INTERFACE);
 
-                gateway = channelConfig.gateway.empty() ?
+                gateway = channelConf->gateway.empty() ?
                         systemProperties["DefaultGateway"].get<std::string>() :
-                        channelConfig.gateway;
-
+                        channelConf->gateway;
             }
         }
 
@@ -248,7 +271,7 @@
                 bus,
                 ipmi::network::ETHERNET_INTERFACE,
                 ipmi::network::ROOT,
-                ipmi::network::INTERFACE);
+                ethdevice);
 
         // setting the physical interface mode to static.
         ipmi::setDbusProperty(bus,
@@ -264,14 +287,14 @@
         ipmi::deleteAllDbusObjects(bus,
                                    ipmi::network::ROOT,
                                    ipmi::network::IP_INTERFACE,
-                                   ipmi::network::IP_TYPE);
+                                   ethIp);
 
         if (vlanID)
         {
             ipmi::network::createVLAN(bus,
                                       ipmi::network::SERVICE,
                                       ipmi::network::ROOT,
-                                      ipmi::network::INTERFACE,
+                                      ethdevice,
                                       vlanID);
 
             auto networkInterfaceObject = ipmi::getDbusObject(
@@ -282,7 +305,7 @@
            networkInterfacePath = networkInterfaceObject.first;
         }
 
-        if (channelConfig.ipsrc == ipmi::network::IPOrigin::DHCP)
+        if (channelConf->ipsrc == ipmi::network::IPOrigin::DHCP)
         {
             ipmi::setDbusProperty(bus,
                                   ipmi::network::SERVICE,
@@ -330,13 +353,13 @@
                         entry("ADDRESS=%s", ipaddress.c_str()),
                         entry("GATEWAY=%s", gateway.c_str()),
                         entry("VLANID=%d", vlanID),
-                        entry("IPSRC=%d", channelConfig.ipsrc));
+                        entry("IPSRC=%d", channelConf->ipsrc));
 
         commit<InternalFailure>();
         rc = IPMI_CC_UNSPECIFIED_ERROR;
     }
 
-    channelConfig.clear();
+    channelConf->clear();
     return rc;
 }
 
@@ -350,17 +373,15 @@
     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;
+    int channel = requestData->channelNumber;
+    auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
 
-    if (requestData->channelNumber != channelOne &&
-        requestData->channelNumber != channelE)
+    if (channel != channelE && ethdevice.empty())
     {
         *data_len = 0;
         return IPMI_CC_INVALID_FIELD_REQUEST;
@@ -406,20 +427,20 @@
         IPMI_CHANNEL_TYPE_IPMB,
         1,0x41,0xA7,0x00,0,0};
     uint8_t *p = (uint8_t*) request;
+    int channel = (*p) & CHANNEL_MASK;
+    std::string ethdevice = ipmi::network::ChanneltoEthernet(channel);
 
     printf("IPMI APP GET CHANNEL INFO\n");
 
-    // The supported channels numbers are 1 and 8.
+    // The supported channels numbers are those which are configured.
     // 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 {
+    if (channel != 0xe && ethdevice.empty()) {
         rc = IPMI_CC_PARM_OUT_OF_RANGE;
         *data_len = 0;
+    } else {
+        *data_len = sizeof(resp);
+        memcpy(response, resp, *data_len);
     }
 
     return rc;
diff --git a/net.cpp b/net.cpp
new file mode 100644
index 0000000..6c492a2
--- /dev/null
+++ b/net.cpp
@@ -0,0 +1,41 @@
+#include <map>
+#include <string>
+
+// Not sure if this should live in utils.  Because it's really a per-system
+// configuration, instead of just hard-coding channel 1 to be eth0, one could
+// conceivably configure it however they pleased.
+//
+// In this design, channel 0 is the in-band host channel.
+
+namespace ipmi
+{
+namespace network
+{
+
+// This map should come from a configuration yaml.
+// Also, no need to really be a map, could be just an array
+// we index into by channel. :D
+std::map<int, std::string> ethDeviceMap = {
+    {1, "eth0"},
+    {2, "eth1"},
+};
+
+
+// Given a channel number, return a matching ethernet device, or empty string
+// if there is no match.
+// TODO provide this from a configuration:
+// https://github.com/openbmc/openbmc/issues/2667
+std::string ChanneltoEthernet(int channel)
+{
+    auto dev = ethDeviceMap.find(channel);
+    if (dev == ethDeviceMap.end())
+    {
+        return "";
+    }
+
+    return dev->second;
+}
+
+} // namespace network
+} // namespace ipmi
+
diff --git a/net.hpp b/net.hpp
new file mode 100644
index 0000000..21131b2
--- /dev/null
+++ b/net.hpp
@@ -0,0 +1,11 @@
+#include <string>
+
+namespace ipmi
+{
+namespace network
+{
+
+std::string ChanneltoEthernet(int channel);
+
+} // namespace network
+} // namespace ipmi
diff --git a/transporthandler.cpp b/transporthandler.cpp
index 50bc473..f4326c1 100644
--- a/transporthandler.cpp
+++ b/transporthandler.cpp
@@ -9,6 +9,7 @@
 #include "ipmid.hpp"
 #include "transporthandler.hpp"
 #include "utils.hpp"
+#include "net.hpp"
 
 #include <phosphor-logging/log.hpp>
 #include <phosphor-logging/elog-errors.hpp>
@@ -23,7 +24,7 @@
 
 const int SIZE_MAC = 18; //xx:xx:xx:xx:xx:xx
 
-struct ChannelConfig_t channelConfig;
+std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig;
 
 using namespace phosphor::logging;
 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
@@ -31,13 +32,34 @@
 
 void register_netfn_transport_functions() __attribute__((constructor));
 
+struct ChannelConfig_t* getChannelConfig(int channel)
+{
+    auto item = channelConfig.find(channel);
+    if (item == channelConfig.end())
+    {
+        channelConfig[channel] = std::make_unique<struct ChannelConfig_t>();
+    }
+
+    return channelConfig[channel].get();
+}
+
 // Helper Function to get IP Address/NetMask/Gateway/MAC Address from Network Manager or
 // Cache based on Set-In-Progress State
-ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t* data)
+ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t* data, int channel)
 {
     ipmi_ret_t rc = IPMI_CC_OK;
     sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
 
+    auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
+    // if ethdevice is an empty string they weren't expecting this channel.
+    if (ethdevice.empty())
+    {
+        // TODO: return error from getNetworkData()
+        return IPMI_CC_INVALID_FIELD_REQUEST;
+    }
+    auto ethIP = ethdevice + "/" + ipmi::network::IP_TYPE;
+    auto channelConf = getChannelConfig(channel);
+
     try
     {
         switch (lan_param)
@@ -45,7 +67,7 @@
             case LAN_PARM_IP:
             {
                 std::string ipaddress;
-                if (channelConfig.lan_set_in_progress == SET_COMPLETE)
+                if (channelConf->lan_set_in_progress == SET_COMPLETE)
                 {
                     try
                     {
@@ -53,7 +75,7 @@
                                 bus,
                                 ipmi::network::IP_INTERFACE,
                                 ipmi::network::ROOT,
-                                ipmi::network::IP_TYPE);
+                                ethIP);
 
                         auto properties = ipmi::getAllDbusProperties(
                                 bus,
@@ -62,7 +84,6 @@
                                 ipmi::network::IP_INTERFACE);
 
                         ipaddress = properties["Address"].get<std::string>();
-
                     }
                     // ignore the exception, as it is a valid condtion that
                     // system is not confiured with any ip.
@@ -71,9 +92,9 @@
                         // nothing to do.
                     }
                 }
-                else if (channelConfig.lan_set_in_progress == SET_IN_PROGRESS)
+                else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
                 {
-                    ipaddress = channelConfig.ipaddr;
+                    ipaddress = channelConf->ipaddr;
                 }
 
                 inet_pton(AF_INET, ipaddress.c_str(),
@@ -85,7 +106,7 @@
             {
                 std::string networkInterfacePath;
 
-                if (channelConfig.lan_set_in_progress == SET_COMPLETE)
+                if (channelConf->lan_set_in_progress == SET_COMPLETE)
                 {
                     try
                     {
@@ -96,7 +117,7 @@
                                 bus,
                                 ipmi::network::IP_INTERFACE,
                                 ipmi::network::ROOT,
-                                ipmi::network::IP_TYPE);
+                                ethIP);
 
                         // Get the parent interface of the IP object.
                         try
@@ -133,7 +154,7 @@
                                 bus,
                                 ipmi::network::ETHERNET_INTERFACE,
                                 ipmi::network::ROOT,
-                                ipmi::network::INTERFACE);
+                                ethdevice);
 
                         networkInterfacePath = networkInterfaceObject.first;
                     }
@@ -152,9 +173,9 @@
 
                     memcpy(data, &ipsrc, ipmi::network::IPSRC_SIZE_BYTE);
                 }
-                else if (channelConfig.lan_set_in_progress == SET_IN_PROGRESS)
+                else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
                 {
-                   memcpy(data, &(channelConfig.ipsrc),
+                   memcpy(data, &(channelConf->ipsrc),
                           ipmi::network::IPSRC_SIZE_BYTE);
                 }
             }
@@ -163,7 +184,7 @@
             case LAN_PARM_SUBNET:
             {
                 unsigned long mask {};
-                if (channelConfig.lan_set_in_progress == SET_COMPLETE)
+                if (channelConf->lan_set_in_progress == SET_COMPLETE)
                 {
                     try
                     {
@@ -191,9 +212,9 @@
                     }
                     memcpy(data, &mask, ipmi::network::IPV4_ADDRESS_SIZE_BYTE);
                 }
-                else if (channelConfig.lan_set_in_progress == SET_IN_PROGRESS)
+                else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
                 {
-                    inet_pton(AF_INET, channelConfig.netmask.c_str(),
+                    inet_pton(AF_INET, channelConf->netmask.c_str(),
                               reinterpret_cast<void*>(data));
                 }
 
@@ -204,7 +225,7 @@
             {
                 std::string gateway;
 
-                if (channelConfig.lan_set_in_progress == SET_COMPLETE)
+                if (channelConf->lan_set_in_progress == SET_COMPLETE)
                 {
                     try
                     {
@@ -230,9 +251,9 @@
                     }
 
                 }
-                else if (channelConfig.lan_set_in_progress == SET_IN_PROGRESS)
+                else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
                 {
-                    gateway = channelConfig.gateway;
+                    gateway = channelConf->gateway;
                 }
 
                 inet_pton(AF_INET, gateway.c_str(),
@@ -243,12 +264,13 @@
             case LAN_PARM_MAC:
             {
                 std::string macAddress;
-                if (channelConfig.lan_set_in_progress == SET_COMPLETE)
+                if (channelConf->lan_set_in_progress == SET_COMPLETE)
                 {
                     auto macObjectInfo = ipmi::getDbusObject(
                                              bus,
                                              ipmi::network::MAC_INTERFACE,
-                                             ipmi::network::ROOT);
+                                             ipmi::network::ROOT,
+                                             ethdevice);
 
                     auto variant = ipmi::getDbusProperty(
                                      bus,
@@ -260,9 +282,9 @@
                     macAddress = variant.get<std::string>();
 
                 }
-                else if (channelConfig.lan_set_in_progress == SET_IN_PROGRESS)
+                else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
                 {
-                    macAddress = channelConfig.macAddress;
+                    macAddress = channelConf->macAddress;
                 }
 
                 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
@@ -278,7 +300,7 @@
             case LAN_PARM_VLAN:
             {
                 uint16_t vlanID {};
-                if (channelConfig.lan_set_in_progress == SET_COMPLETE)
+                if (channelConf->lan_set_in_progress == SET_COMPLETE)
                 {
                     try
                     {
@@ -308,9 +330,9 @@
 
                     memcpy(data, &vlanID, ipmi::network::VLAN_SIZE_BYTE);
                 }
-                else if (channelConfig.lan_set_in_progress == SET_IN_PROGRESS)
+                else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
                 {
-                    memcpy(data, &(channelConfig.vlanID),
+                    memcpy(data, &(channelConf->vlanID),
                            ipmi::network::VLAN_SIZE_BYTE);
                 }
             }
@@ -364,6 +386,15 @@
     auto reqptr = reinterpret_cast<const set_lan_t*>(request);
     sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
 
+    // channel number is the lower nibble
+    int channel = reqptr->channel & CHANNEL_MASK;
+    auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
+    if (ethdevice.empty())
+    {
+        return IPMI_CC_INVALID_FIELD_REQUEST;
+    }
+    auto channelConf = getChannelConfig(channel);
+
     switch (reqptr->parameter)
     {
         case LAN_PARM_IP:
@@ -372,8 +403,7 @@
                      reqptr->data[0], reqptr->data[1],
                      reqptr->data[2], reqptr->data[3]);
 
-            channelConfig.ipaddr.assign(ipaddr);
-
+            channelConf->ipaddr.assign(ipaddr);
         }
         break;
 
@@ -381,7 +411,7 @@
         {
             uint8_t ipsrc{};
             memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE);
-            channelConfig.ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc);
+            channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc);
         }
         break;
 
@@ -401,7 +431,7 @@
                                      bus,
                                      ipmi::network::MAC_INTERFACE,
                                      ipmi::network::ROOT,
-                                     ipmi::network::INTERFACE);
+                                     ethdevice);
 
             ipmi::setDbusProperty(bus,
                                   macObjectInfo.second,
@@ -410,8 +440,7 @@
                                   "MACAddress",
                                   std::string(mac));
 
-            channelConfig.macAddress = mac;
-
+            channelConf->macAddress = mac;
         }
         break;
 
@@ -420,7 +449,7 @@
             snprintf(netmask, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
                      reqptr->data[0], reqptr->data[1],
                      reqptr->data[2], reqptr->data[3]);
-            channelConfig.netmask.assign(netmask);
+            channelConf->netmask.assign(netmask);
         }
         break;
 
@@ -429,8 +458,7 @@
             snprintf(gateway, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
                      reqptr->data[0], reqptr->data[1],
                      reqptr->data[2], reqptr->data[3]);
-            channelConfig.gateway.assign(gateway);
-
+            channelConf->gateway.assign(gateway);
         }
         break;
 
@@ -442,7 +470,7 @@
             // We assume that ipmitool always send enable
             // bit as 1.
             vlan = le16toh(vlan);
-            channelConfig.vlanID = vlan;
+            channelConf->vlanID = vlan;
         }
         break;
 
@@ -450,22 +478,20 @@
         {
             if (reqptr->data[0] == SET_COMPLETE)
             {
-                channelConfig.lan_set_in_progress = SET_COMPLETE;
+                channelConf->lan_set_in_progress = SET_COMPLETE;
 
                 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("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));
 
                 log<level::INFO>("Use Set Channel Access command to apply");
-
             }
             else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress
             {
-                channelConfig.lan_set_in_progress = SET_IN_PROGRESS;
+                channelConf->lan_set_in_progress = SET_IN_PROGRESS;
             }
-
         }
         break;
 
@@ -473,7 +499,6 @@
         {
             rc = IPMI_CC_PARM_NOT_SUPPORTED;
         }
-
     }
 
     return rc;
@@ -499,6 +524,8 @@
     const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0
 
     get_lan_t *reqptr = (get_lan_t*) request;
+    // channel number is the lower nibble
+    int channel = reqptr->rev_channel & CHANNEL_MASK;
 
     if (reqptr->rev_channel & 0x80) // Revision is bit 7
     {
@@ -508,9 +535,16 @@
         return IPMI_CC_OK;
     }
 
+    auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
+    if (ethdevice.empty())
+    {
+        return IPMI_CC_INVALID_FIELD_REQUEST;
+    }
+    auto channelConf = getChannelConfig(channel);
+
     if (reqptr->parameter == LAN_PARM_INPROGRESS)
     {
-        uint8_t buf[] = {current_revision, channelConfig.lan_set_in_progress};
+        uint8_t buf[] = {current_revision, channelConf->lan_set_in_progress};
         *data_len = sizeof(buf);
         memcpy(response, &buf, *data_len);
     }
@@ -536,7 +570,7 @@
         *data_len = sizeof(current_revision);
         memcpy(buf, &current_revision, *data_len);
 
-        if (getNetworkData(reqptr->parameter, &buf[1]) == IPMI_CC_OK)
+        if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK)
         {
             if (reqptr->parameter == LAN_PARM_MAC)
             {
@@ -559,7 +593,7 @@
 
         *data_len = sizeof(current_revision);
         memcpy(buf, &current_revision, *data_len);
-        if (getNetworkData(reqptr->parameter, &buf[1]) == IPMI_CC_OK)
+        if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK)
         {
             *data_len = sizeof(buf);
             memcpy(response, &buf, *data_len);
@@ -570,7 +604,7 @@
         uint8_t buff[ipmi::network::IPSRC_SIZE_BYTE + 1] = {};
         *data_len = sizeof(current_revision);
         memcpy(buff, &current_revision, *data_len);
-        if (getNetworkData(reqptr->parameter, &buff[1]) == IPMI_CC_OK)
+        if (getNetworkData(reqptr->parameter, &buff[1], channel) == IPMI_CC_OK)
         {
             *data_len = sizeof(buff);
             memcpy(response, &buff, *data_len);
diff --git a/transporthandler.hpp b/transporthandler.hpp
index a101794..42bf717 100644
--- a/transporthandler.hpp
+++ b/transporthandler.hpp
@@ -32,6 +32,9 @@
 constexpr uint8_t SET_COMMIT_WRITE = 2; //Optional
 constexpr uint8_t SET_IN_PROGRESS_RESERVED = 3; //Reserved
 
+const int CHANNEL_MASK = 0x0f;
+const int NUM_CHANNELS = 0x0f;
+
 struct ChannelConfig_t
 {
     std::string ipaddr;
@@ -56,3 +59,10 @@
         lan_set_in_progress = SET_COMPLETE;
     }
 };
+
+// Given a channel, get the corresponding configuration,
+// or allocate it first.
+//
+// @param[in] channel the channel
+// @return the ChannelConfig_t pointer.
+struct ChannelConfig_t* getChannelConfig(int channel);
diff --git a/utils.hpp b/utils.hpp
index 55978fb..1699c52 100644
--- a/utils.hpp
+++ b/utils.hpp
@@ -161,7 +161,6 @@
 
 constexpr auto ROOT = "/xyz/openbmc_project/network";
 constexpr auto SERVICE = "xyz.openbmc_project.Network";
-constexpr auto INTERFACE = "eth0";
 constexpr auto IP_TYPE = "ipv4";
 constexpr auto IPV4_PREFIX = "169.254";
 constexpr auto IPV6_PREFIX = "fe80";