Don't set/get zeroconfig address if other IP address is present

Resolves openbmc/openbmc#2265

Change-Id: I65b54358f13231c78b3c6488a59b94bc9323484c
Signed-off-by: Nagaraju Goruganti <ngorugan@in.ibm.com>
diff --git a/apphandler.cpp b/apphandler.cpp
index 210544c..29adfa4 100644
--- a/apphandler.cpp
+++ b/apphandler.cpp
@@ -695,8 +695,11 @@
                             ipmi::network::IP_INTERFACE);
 
                     ipaddress = channelConfig.ipaddr.empty() ?
-                        properties["Address"].get<std::string>() :
-                        channelConfig.ipaddr;
+                                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>() :
diff --git a/transporthandler.cpp b/transporthandler.cpp
index e571d30..77c3849 100644
--- a/transporthandler.cpp
+++ b/transporthandler.cpp
@@ -63,19 +63,11 @@
                 {
                     try
                     {
-                        auto ipObjectInfo = ipmi::getDbusObject(
-                                bus,
-                                ipmi::network::IP_INTERFACE,
-                                ipmi::network::ROOT,
-                                ipmi::network::IP_TYPE);
+                        ipaddress = ipmi::getIPAddress(bus,
+                                                       ipmi::network::IP_INTERFACE,
+                                                       ipmi::network::ROOT,
+                                                       ipmi::network::IP_TYPE);
 
-                        auto properties = ipmi::getAllDbusProperties(
-                                bus,
-                                ipObjectInfo.second,
-                                ipObjectInfo.first,
-                                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.
diff --git a/utils.cpp b/utils.cpp
index 2124af9..82497a3 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -13,6 +13,15 @@
 using namespace phosphor::logging;
 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
 
+namespace network
+{
+
+/** @brief checks if the given ip is Link Local Ip or not.
+  *  @param[in] ipaddress - IPAddress.
+  */
+bool isLinkLocalIP(const std::string& ipaddress);
+
+}
 
 //TODO There may be cases where an interface is implemented by multiple
 //  objects,to handle such cases we are interested on that object
@@ -87,6 +96,49 @@
 
 }
 
+std::string getIPAddress(sdbusplus::bus::bus& bus,
+                         const std::string& interface,
+                         const std::string& serviceRoot,
+                         const std::string& match)
+{
+    auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, match);
+
+    if (objectTree.empty())
+    {
+        log<level::ERR>("No Object has implemented the IP interface",
+                        entry("INTERFACE=%s", interface.c_str()));
+        elog<InternalFailure>();
+    }
+
+    std::string ipaddress;
+
+    for (auto& object : objectTree)
+    {
+        auto variant = ipmi::getDbusProperty(
+                           bus,
+                           object.second.begin()->first,
+                           object.first,
+                           ipmi::network::IP_INTERFACE,
+                           "Address");
+
+        ipaddress = std::move(variant.get<std::string>());
+
+        // if LinkLocalIP found look for Non-LinkLocalIP
+        if (ipmi::network::isLinkLocalIP(ipaddress))
+        {
+            continue;
+        }
+        else
+        {
+            break;
+        }
+
+    }
+
+    return ipaddress;
+
+}
+
 Value getDbusProperty(sdbusplus::bus::bus& bus,
                       const std::string& service,
                       const std::string& objPath,
@@ -355,6 +407,11 @@
 namespace network
 {
 
+bool isLinkLocalIP(const std::string& address)
+{
+    return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
+}
+
 void createIP(sdbusplus::bus::bus& bus,
               const std::string& service,
               const std::string& objPath,
diff --git a/utils.hpp b/utils.hpp
index b50fde7..265a555 100644
--- a/utils.hpp
+++ b/utils.hpp
@@ -45,6 +45,20 @@
                              const std::string& subtreePath = ROOT,
                              const std::string& match = {});
 
+/** @brief Gets the ipAddres of first dbus IP object of Non-LinkLocalIPAddress
+ *         type from the given subtree, if not avalable gets IP object of
+ *         LinkLocalIPAddress type.
+ *  @param[in] bus - DBUS Bus Object.
+ *  @param[in] interface - Dbus interface.
+ *  @param[in] subtreePath - subtree from where the search should start.
+ *  @param[in] match - identifier for object.
+ *  @return On success returns the ipAddress.
+ */
+std::string getIPAddress(sdbusplus::bus::bus& bus,
+                         const std::string& interface,
+                         const std::string& subtreePath,
+                         const std::string& match);
+
 /** @brief Gets the value associated with the given object
  *         and the interface.
  *  @param[in] bus - DBUS Bus Object.
@@ -149,6 +163,8 @@
 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";
 constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP";
 constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress";
 constexpr auto SYSTEMCONFIG_INTERFACE = "xyz.openbmc_project.Network.SystemConfiguration";