Implement EthernetInterface

Change-Id: I8d57ee3565e43e6e4463286c220dd54d72da049f
Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp
new file mode 100644
index 0000000..3fcb489
--- /dev/null
+++ b/ethernet_interface.cpp
@@ -0,0 +1,141 @@
+#include "ethernet_interface.hpp"
+
+#include <phosphor-logging/log.hpp>
+
+#include <linux/ethtool.h>
+#include <net/if.h>
+#include <linux/sockios.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+namespace phosphor
+{
+namespace network
+{
+
+using namespace phosphor::logging;
+constexpr auto MAC_ADDRESS_FORMAT = "%02X:%02X:%02X:%02X:%02X:%02X";
+constexpr size_t SIZE_MAC = 18;
+constexpr size_t SIZE_BUFF = 512;
+
+EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
+                                     const std::string& objPath,
+                                     bool dhcpEnabled) :
+    details::EthernetIface(bus, objPath.c_str(), true)
+{
+    auto intfName = objPath.substr(objPath.rfind("/") + 1);
+    interfaceName(intfName);
+    dHCPEnabled(dhcpEnabled);
+    mACAddress(getMACAddress());
+    // Emit deferred signal.
+    this->emit_object_added();
+}
+
+/*
+Note: We don't have support for  ethtool now
+will enable this code once we bring the ethtool
+in the image.
+TODO: https://github.com/openbmc/openbmc/issues/1484
+*/
+InterfaceInfo EthernetInterface::getInterfaceInfo() const
+{
+    int sock{-1};
+    struct ifreq ifr{0};
+    struct ethtool_cmd edata{0};
+    LinkSpeed speed {0};
+    Autoneg autoneg {0};
+    DuplexMode duplex {0};
+    do
+    {
+        sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+        if (sock < 0)
+        {
+            log<level::ERR>("socket creation  failed:",
+                            entry("ERROR=%s", strerror(errno)));
+            break;
+        }
+
+        strncpy(ifr.ifr_name, interfaceName().c_str(), sizeof(ifr.ifr_name));
+        ifr.ifr_data = reinterpret_cast<char*>(&edata);
+
+        edata.cmd = ETHTOOL_GSET;
+
+        if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
+        {
+            log<level::ERR>("ioctl failed for SIOCETHTOOL:",
+                            entry("ERROR=%s", strerror(errno)));
+            break;
+
+        }
+        speed = edata.speed;
+        duplex = edata.duplex;
+        autoneg = edata.autoneg;
+    }
+    while (0);
+
+    if (sock)
+    {
+        close(sock);
+    }
+    return std::make_tuple(speed, duplex, autoneg);
+}
+
+/** @brief get the mac address of the interface.
+ *  @return macaddress on success
+ */
+
+std::string EthernetInterface::getMACAddress() const
+{
+    struct ifreq ifr;
+    struct ifconf ifc;
+    char buf[SIZE_BUFF];
+    char macAddress[SIZE_MAC] = "";
+
+    int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+    if (sock < 0)
+    {
+        log<level::ERR>("socket creation  failed:",
+                        entry("ERROR=%s", strerror(errno)));
+        return macAddress;
+    }
+
+    ifc.ifc_len = sizeof(buf);
+    ifc.ifc_buf = buf;
+    if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
+    {
+        log<level::ERR>("ioctl failed for SIOCGIFCONF:",
+                        entry("ERROR=%s", strerror(errno)));
+        return macAddress;
+    }
+
+    struct ifreq* it = ifc.ifc_req;
+    const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
+
+    for (; it != end; ++it)
+    {
+        if (interfaceName() == it->ifr_name)
+        {
+            break;
+        }
+    }
+    if (interfaceName() == it->ifr_name)
+    {
+        strcpy(ifr.ifr_name, it->ifr_name);
+        if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
+        {
+            log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
+                            entry("ERROR=%s", strerror(errno)));
+            return macAddress;
+        }
+
+        snprintf(macAddress, SIZE_MAC, MAC_ADDRESS_FORMAT,
+                 ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1],
+                 ifr.ifr_hwaddr.sa_data[2], ifr.ifr_hwaddr.sa_data[3],
+                 ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]);
+    }
+    return macAddress;
+}
+}//namespace network
+}//namespace phosphor