[connman] Added Tizen Wi-Fi Mesh
[platform/upstream/connman.git] / src / inet.c
index a36642a..25e5372 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  Connection Manager
  *
- *  Copyright (C) 2007-2012  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2007-2013  Intel Corporation. All rights reserved.
  *  Copyright (C) 2003-2005  Go-Core Project
  *  Copyright (C) 2003-2006  Helsinki University of Technology
  *
 #include <fcntl.h>
 #include <linux/if_tun.h>
 #include <ctype.h>
+#include <ifaddrs.h>
+#include <linux/fib_rules.h>
 
 #include "connman.h"
+#include <gdhcp/gdhcp.h>
 
 #define NLMSG_TAIL(nmsg)                               \
        ((struct rtattr *) (((uint8_t*) (nmsg)) +       \
@@ -95,7 +98,7 @@ int __connman_inet_modify_address(int cmd, int flags,
                "prefixlen %hhu broadcast %s", cmd, flags, index, family,
                address, peer, prefixlen, broadcast);
 
-       if (address == NULL)
+       if (!address)
                return -EINVAL;
 
        if (family != AF_INET && family != AF_INET6)
@@ -120,13 +123,13 @@ int __connman_inet_modify_address(int cmd, int flags,
                if (inet_pton(AF_INET, address, &ipv4_addr) < 1)
                        return -1;
 
-               if (broadcast != NULL)
+               if (broadcast)
                        inet_pton(AF_INET, broadcast, &ipv4_bcast);
                else
                        ipv4_bcast.s_addr = ipv4_addr.s_addr |
                                htonl(0xfffffffflu >> prefixlen);
 
-               if (peer != NULL) {
+               if (peer) {
                        if (inet_pton(AF_INET, peer, &ipv4_dest) < 1)
                                return -1;
 
@@ -187,12 +190,84 @@ done:
        return err;
 }
 
+#if defined TIZEN_EXT_WIFI_MESH
+char *connman_inet_ifaddr(const char *name)
+{
+       struct ifreq ifr;
+       struct ether_addr eth;
+       char *str;
+       int sk, err;
+
+       sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+       if (sk < 0)
+               return NULL;
+
+       strncpy(ifr.ifr_name, name, IFNAMSIZ-1);
+
+       err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+       close(sk);
+
+       if (err < 0)
+               return NULL;
+
+       str = g_malloc(18);
+       if (!str)
+               return NULL;
+
+       memcpy(&eth, &ifr.ifr_hwaddr.sa_data, sizeof(eth));
+       snprintf(str, 13, "%02x%02x%02x%02x%02x%02x",
+                                               eth.ether_addr_octet[0],
+                                               eth.ether_addr_octet[1],
+                                               eth.ether_addr_octet[2],
+                                               eth.ether_addr_octet[3],
+                                               eth.ether_addr_octet[4],
+                                               eth.ether_addr_octet[5]);
+
+       return str;
+}
+
+char *connman_inet_ifname2addr(const char *name)
+{
+       struct ifreq ifr;
+       struct ether_addr eth;
+       char *str;
+       int sk, err;
+
+       sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+       if (sk < 0)
+               return NULL;
+
+       strncpy(ifr.ifr_name, name, IFNAMSIZ-1);
+
+       err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+       close(sk);
+
+       if (err < 0)
+               return NULL;
+
+       str = g_malloc(18);
+       if (!str)
+               return NULL;
+
+       memcpy(&eth, &ifr.ifr_hwaddr.sa_data, sizeof(eth));
+       snprintf(str, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
+                                               eth.ether_addr_octet[0],
+                                               eth.ether_addr_octet[1],
+                                               eth.ether_addr_octet[2],
+                                               eth.ether_addr_octet[3],
+                                               eth.ether_addr_octet[4],
+                                               eth.ether_addr_octet[5]);
+
+       return str;
+}
+#endif
+
 int connman_inet_ifindex(const char *name)
 {
        struct ifreq ifr;
        int sk, err;
 
-       if (name == NULL)
+       if (!name)
                return -1;
 
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
@@ -200,7 +275,7 @@ int connman_inet_ifindex(const char *name)
                return -1;
 
        memset(&ifr, 0, sizeof(ifr));
-       strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+       strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name) - 1);
 
        err = ioctl(sk, SIOCGIFINDEX, &ifr);
 
@@ -237,36 +312,6 @@ char *connman_inet_ifname(int index)
        return g_strdup(ifr.ifr_name);
 }
 
-short int connman_inet_ifflags(int index)
-{
-       struct ifreq ifr;
-       int sk, err;
-
-       sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-       if (sk < 0)
-               return -errno;
-
-       memset(&ifr, 0, sizeof(ifr));
-       ifr.ifr_ifindex = index;
-
-       if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
-               err = -errno;
-               goto done;
-       }
-
-       if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
-               err = -errno;
-               goto done;
-       }
-
-       err = ifr.ifr_flags;
-
-done:
-       close(sk);
-
-       return err;
-}
-
 int connman_inet_ifup(int index)
 {
        struct ifreq ifr;
@@ -333,7 +378,7 @@ int connman_inet_ifdown(int index)
        }
 
        memset(&addr_ifr, 0, sizeof(addr_ifr));
-       memcpy(&addr_ifr.ifr_name, &ifr.ifr_name, sizeof(ifr.ifr_name));
+       memcpy(&addr_ifr.ifr_name, &ifr.ifr_name, sizeof(ifr.ifr_name) - 1);
        addr = (struct sockaddr_in *)&addr_ifr.ifr_addr;
        addr->sin_family = AF_INET;
        if (ioctl(sk, SIOCSIFADDR, &addr_ifr) < 0)
@@ -357,35 +402,45 @@ done:
        return err;
 }
 
-connman_bool_t connman_inet_is_cfg80211(int index)
+#if defined TIZEN_EXT
+void connman_inet_update_device_ident(struct connman_device *device)
 {
-       connman_bool_t result = FALSE;
-       char phy80211_path[PATH_MAX];
-       struct stat st;
-       struct ifreq ifr;
-       int sk;
-
-       sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-       if (sk < 0)
-               return FALSE;
-
-       memset(&ifr, 0, sizeof(ifr));
-       ifr.ifr_ifindex = index;
-
-       if (ioctl(sk, SIOCGIFNAME, &ifr) < 0)
-               goto done;
-
-       snprintf(phy80211_path, PATH_MAX,
-                               "/sys/class/net/%s/phy80211", ifr.ifr_name);
-
-       if (stat(phy80211_path, &st) == 0 && (st.st_mode & S_IFDIR))
-               result = TRUE;
+       int index;
+       enum connman_device_type type;
+       char *ident = NULL, *addr = NULL;
+
+       index = connman_device_get_index(device);
+       type = connman_device_get_type(device);
+
+       switch (type) {
+       case CONNMAN_DEVICE_TYPE_UNKNOWN:
+               return;
+       case CONNMAN_DEVICE_TYPE_ETHERNET:
+       case CONNMAN_DEVICE_TYPE_GADGET:
+       case CONNMAN_DEVICE_TYPE_WIFI:
+               addr = index2addr(index);
+               ident = index2ident(index, NULL);
+               break;
+       case CONNMAN_DEVICE_TYPE_CELLULAR:
+               ident = index2ident(index, NULL);
+               break;
+       case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+       case CONNMAN_DEVICE_TYPE_GPS:
+       case CONNMAN_DEVICE_TYPE_VENDOR:
+               break;
+       }
 
-done:
-       close(sk);
+       if (ident != NULL) {
+               connman_device_set_ident(device, ident);
+               g_free(ident);
+       }
 
-       return result;
+       if (addr != NULL) {
+               connman_device_set_string(device, "Address", addr);
+               g_free(addr);
+       }
 }
+#endif
 
 struct in6_ifreq {
        struct in6_addr ifr6_addr;
@@ -400,7 +455,7 @@ int connman_inet_set_ipv6_address(int index,
        unsigned char prefix_len;
        const char *address;
 
-       if (ipaddress->local == NULL)
+       if (!ipaddress->local)
                return 0;
 
        prefix_len = ipaddress->prefixlen;
@@ -425,7 +480,7 @@ int connman_inet_set_address(int index, struct connman_ipaddress *ipaddress)
        unsigned char prefix_len;
        const char *address, *broadcast, *peer;
 
-       if (ipaddress->local == NULL)
+       if (!ipaddress->local)
                return -1;
 
        prefix_len = ipaddress->prefixlen;
@@ -453,6 +508,9 @@ int connman_inet_clear_ipv6_address(int index, const char *address,
 
        DBG("index %d address %s prefix_len %d", index, address, prefix_len);
 
+       if (!address)
+               return -EINVAL;
+
        err = __connman_inet_modify_address(RTM_DELADDR, 0, index, AF_INET6,
                                address, NULL, prefix_len, NULL);
        if (err < 0) {
@@ -474,7 +532,11 @@ int connman_inet_clear_address(int index, struct connman_ipaddress *ipaddress)
        broadcast = ipaddress->broadcast;
        peer = ipaddress->peer;
 
-       DBG("index %d address %s prefix_len %d", index, address, prefix_len);
+       DBG("index %d address %s prefix_len %d peer %s broadcast %s", index,
+               address, prefix_len, peer, broadcast);
+
+       if (!address)
+               return -EINVAL;
 
        err = __connman_inet_modify_address(RTM_DELADDR, 0, index, AF_INET,
                                address, peer, prefix_len, broadcast);
@@ -504,30 +566,33 @@ int connman_inet_add_network_route(int index, const char *host,
        struct ifreq ifr;
        struct rtentry rt;
        struct sockaddr_in addr;
-       int sk, err;
+       int sk, err = 0;
 
        DBG("index %d host %s gateway %s netmask %s", index,
                host, gateway, netmask);
 
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-       if (sk < 0)
-               return -1;
+       if (sk < 0) {
+               err = -errno;
+               goto out;
+       }
 
        memset(&ifr, 0, sizeof(ifr));
        ifr.ifr_ifindex = index;
 
        if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+               err = -errno;
                close(sk);
-               return -1;
+               goto out;
        }
 
        DBG("ifname %s", ifr.ifr_name);
 
        memset(&rt, 0, sizeof(rt));
        rt.rt_flags = RTF_UP;
-       if (gateway != NULL)
+       if (gateway)
                rt.rt_flags |= RTF_GATEWAY;
-       if (netmask == NULL)
+       if (!netmask)
                rt.rt_flags |= RTF_HOST;
 
        memset(&addr, 0, sizeof(addr));
@@ -537,7 +602,7 @@ int connman_inet_add_network_route(int index, const char *host,
 
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
-       if (gateway != NULL)
+       if (gateway)
                addr.sin_addr.s_addr = inet_addr(gateway);
        else
                addr.sin_addr.s_addr = INADDR_ANY;
@@ -546,7 +611,7 @@ int connman_inet_add_network_route(int index, const char *host,
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = INADDR_ANY;
-       if (netmask != NULL)
+       if (netmask)
                addr.sin_addr.s_addr = inet_addr(netmask);
        else
                addr.sin_addr.s_addr = INADDR_ANY;
@@ -554,13 +619,16 @@ int connman_inet_add_network_route(int index, const char *host,
 
        rt.rt_dev = ifr.ifr_name;
 
-       err = ioctl(sk, SIOCADDRT, &rt);
-       if (err < 0)
-               connman_error("Adding host route failed (%s)",
-                                                       strerror(errno));
+       if (ioctl(sk, SIOCADDRT, &rt) < 0 && errno != EEXIST)
+               err = -errno;
 
        close(sk);
 
+out:
+       if (err < 0)
+               connman_error("Adding host route failed (%s)",
+                                                       strerror(-err));
+
        return err;
 }
 
@@ -569,20 +637,23 @@ int connman_inet_del_network_route(int index, const char *host)
        struct ifreq ifr;
        struct rtentry rt;
        struct sockaddr_in addr;
-       int sk, err;
+       int sk, err = 0;
 
        DBG("index %d host %s", index, host);
 
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-       if (sk < 0)
-               return -1;
+       if (sk < 0) {
+               err = -errno;
+               goto out;
+       }
 
        memset(&ifr, 0, sizeof(ifr));
        ifr.ifr_ifindex = index;
 
        if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+               err = -errno;
                close(sk);
-               return -1;
+               goto out;
        }
 
        DBG("ifname %s", ifr.ifr_name);
@@ -597,13 +668,16 @@ int connman_inet_del_network_route(int index, const char *host)
 
        rt.rt_dev = ifr.ifr_name;
 
-       err = ioctl(sk, SIOCDELRT, &rt);
-       if (err < 0)
-               connman_error("Deleting host route failed (%s)",
-                                                       strerror(errno));
+       if (ioctl(sk, SIOCDELRT, &rt) < 0 && errno != ESRCH)
+               err = -errno;
 
        close(sk);
 
+out:
+       if (err < 0)
+               connman_error("Deleting host route failed (%s)",
+                                                       strerror(-err));
+
        return err;
 }
 
@@ -611,20 +685,21 @@ int connman_inet_del_ipv6_network_route(int index, const char *host,
                                                unsigned char prefix_len)
 {
        struct in6_rtmsg rt;
-       int sk, err;
+       int sk, err = 0;
 
        DBG("index %d host %s", index, host);
 
-       if (host == NULL)
+       if (!host)
                return -EINVAL;
 
        memset(&rt, 0, sizeof(rt));
 
        rt.rtmsg_dst_len = prefix_len;
 
-       err = inet_pton(AF_INET6, host, &rt.rtmsg_dst);
-       if (err < 0)
+       if (inet_pton(AF_INET6, host, &rt.rtmsg_dst) < 0) {
+               err = -errno;
                goto out;
+       }
 
        rt.rtmsg_flags = RTF_UP | RTF_HOST;
 
@@ -633,16 +708,19 @@ int connman_inet_del_ipv6_network_route(int index, const char *host,
 
        sk = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0) {
-               err = -1;
+               err = -errno;
                goto out;
        }
 
-       err = ioctl(sk, SIOCDELRT, &rt);
+       if (ioctl(sk, SIOCDELRT, &rt) < 0 && errno != ESRCH)
+               err = -errno;
+
        close(sk);
+
 out:
        if (err < 0)
                connman_error("Del IPv6 host route error (%s)",
-                                               strerror(errno));
+                                               strerror(-err));
 
        return err;
 }
@@ -657,24 +735,25 @@ int connman_inet_add_ipv6_network_route(int index, const char *host,
                                        unsigned char prefix_len)
 {
        struct in6_rtmsg rt;
-       int sk, err;
+       int sk, err = 0;
 
        DBG("index %d host %s gateway %s", index, host, gateway);
 
-       if (host == NULL)
+       if (!host)
                return -EINVAL;
 
        memset(&rt, 0, sizeof(rt));
 
        rt.rtmsg_dst_len = prefix_len;
 
-       err = inet_pton(AF_INET6, host, &rt.rtmsg_dst);
-       if (err < 0)
+       if (inet_pton(AF_INET6, host, &rt.rtmsg_dst) < 0) {
+               err = -errno;
                goto out;
+       }
 
        rt.rtmsg_flags = RTF_UP | RTF_HOST;
 
-       if (gateway != NULL) {
+       if (gateway) {
                rt.rtmsg_flags |= RTF_GATEWAY;
                inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway);
        }
@@ -684,16 +763,19 @@ int connman_inet_add_ipv6_network_route(int index, const char *host,
 
        sk = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0) {
-               err = -1;
+               err = -errno;
                goto out;
        }
 
-       err = ioctl(sk, SIOCADDRT, &rt);
+       if (ioctl(sk, SIOCADDRT, &rt) < 0 && errno != EEXIST)
+               err = -errno;
+
        close(sk);
+
 out:
        if (err < 0)
                connman_error("Set IPv6 host route error (%s)",
-                                               strerror(errno));
+                                               strerror(-err));
 
        return err;
 }
@@ -704,58 +786,22 @@ int connman_inet_add_ipv6_host_route(int index, const char *host,
        return connman_inet_add_ipv6_network_route(index, host, gateway, 128);
 }
 
-int connman_inet_set_ipv6_gateway_address(int index, const char *gateway)
-{
-       struct in6_rtmsg rt;
-       int sk, err;
-
-       DBG("index %d gateway %s", index, gateway);
-
-       if (gateway == NULL)
-               return -EINVAL;
-
-       memset(&rt, 0, sizeof(rt));
-
-       err = inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway);
-       if (err < 0)
-               goto out;
-
-       rt.rtmsg_flags = RTF_UP | RTF_GATEWAY;
-       rt.rtmsg_metric = 1;
-       rt.rtmsg_dst_len = 0;
-       rt.rtmsg_ifindex = index;
-
-       sk = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-       if (sk < 0) {
-               err = -1;
-               goto out;
-       }
-
-       err = ioctl(sk, SIOCADDRT, &rt);
-       close(sk);
-out:
-       if (err < 0)
-               connman_error("Set default IPv6 gateway error (%s)",
-                                               strerror(errno));
-
-       return err;
-}
-
 int connman_inet_clear_ipv6_gateway_address(int index, const char *gateway)
 {
        struct in6_rtmsg rt;
-       int sk, err;
+       int sk, err = 0;
 
        DBG("index %d gateway %s", index, gateway);
 
-       if (gateway == NULL)
+       if (!gateway)
                return -EINVAL;
 
        memset(&rt, 0, sizeof(rt));
 
-       err = inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway);
-       if (err < 0)
+       if (inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway) < 0) {
+               err = -errno;
                goto out;
+       }
 
        rt.rtmsg_flags = RTF_UP | RTF_GATEWAY;
        rt.rtmsg_metric = 1;
@@ -764,90 +810,98 @@ int connman_inet_clear_ipv6_gateway_address(int index, const char *gateway)
 
        sk = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0) {
-               err = -1;
+               err = -errno;
                goto out;
        }
 
-       err = ioctl(sk, SIOCDELRT, &rt);
+       if (ioctl(sk, SIOCDELRT, &rt) < 0 && errno != ESRCH)
+               err = -errno;
+
        close(sk);
+
 out:
        if (err < 0)
                connman_error("Clear default IPv6 gateway error (%s)",
-                                               strerror(errno));
+                                               strerror(-err));
 
        return err;
 }
 
-int connman_inet_set_gateway_address(int index, const char *gateway)
+int connman_inet_set_gateway_interface(int index)
 {
        struct ifreq ifr;
        struct rtentry rt;
        struct sockaddr_in addr;
-       int sk, err;
+       int sk, err = 0;
 
-       DBG("index %d gateway %s", index, gateway);
+       DBG("index %d", index);
 
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-       if (sk < 0)
-               return -1;
+       if (sk < 0) {
+               err = -errno;
+               goto out;
+       }
 
        memset(&ifr, 0, sizeof(ifr));
        ifr.ifr_ifindex = index;
 
        if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+               err = -errno;
                close(sk);
-               return -1;
+               goto out;
        }
 
        DBG("ifname %s", ifr.ifr_name);
 
        memset(&rt, 0, sizeof(rt));
-       rt.rt_flags = RTF_UP | RTF_GATEWAY;
+       rt.rt_flags = RTF_UP;
 
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = INADDR_ANY;
-       memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
 
-       memset(&addr, 0, sizeof(addr));
-       addr.sin_family = AF_INET;
-       addr.sin_addr.s_addr = inet_addr(gateway);
+       memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
+       memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
        memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
 
-       memset(&addr, 0, sizeof(addr));
-       addr.sin_family = AF_INET;
-       addr.sin_addr.s_addr = INADDR_ANY;
-       memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
+       rt.rt_dev = ifr.ifr_name;
 
-       err = ioctl(sk, SIOCADDRT, &rt);
-       if (err < 0)
-               connman_error("Setting default gateway route failed (%s)",
-                                                       strerror(errno));
+       if (ioctl(sk, SIOCADDRT, &rt) < 0 && errno != EEXIST)
+               err = -errno;
 
        close(sk);
 
+out:
+       if (err < 0)
+               connman_error("Setting default interface route failed (%s)",
+                                                       strerror(-err));
+
        return err;
 }
 
-int connman_inet_set_gateway_interface(int index)
+int connman_inet_set_ipv6_gateway_interface(int index)
 {
        struct ifreq ifr;
        struct rtentry rt;
-       struct sockaddr_in addr;
-       int sk, err;
+       struct sockaddr_in6 addr;
+       const struct in6_addr any = IN6ADDR_ANY_INIT;
+       int sk, err = 0;
 
        DBG("index %d", index);
 
-       sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-       if (sk < 0)
-               return -1;
+       sk = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+       if (sk < 0) {
+               err = -errno;
+               goto out;
+       }
 
        memset(&ifr, 0, sizeof(ifr));
        ifr.ifr_ifindex = index;
 
        if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+               err = -errno;
                close(sk);
-               return -1;
+               goto out;
        }
 
        DBG("ifname %s", ifr.ifr_name);
@@ -856,8 +910,8 @@ int connman_inet_set_gateway_interface(int index)
        rt.rt_flags = RTF_UP;
 
        memset(&addr, 0, sizeof(addr));
-       addr.sin_family = AF_INET;
-       addr.sin_addr.s_addr = INADDR_ANY;
+       addr.sin6_family = AF_INET6;
+       addr.sin6_addr = any;
 
        memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
        memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
@@ -865,57 +919,15 @@ int connman_inet_set_gateway_interface(int index)
 
        rt.rt_dev = ifr.ifr_name;
 
-       err = ioctl(sk, SIOCADDRT, &rt);
+       if (ioctl(sk, SIOCADDRT, &rt) < 0 && errno != EEXIST)
+               err = -errno;
+
+       close(sk);
+
+out:
        if (err < 0)
                connman_error("Setting default interface route failed (%s)",
-                                                       strerror(errno));
-       close(sk);
-
-       return err;
-}
-
-int connman_inet_set_ipv6_gateway_interface(int index)
-{
-       struct ifreq ifr;
-       struct rtentry rt;
-       struct sockaddr_in6 addr;
-       const struct in6_addr any = IN6ADDR_ANY_INIT;
-       int sk, err;
-
-       DBG("index %d", index);
-
-       sk = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-       if (sk < 0)
-               return -1;
-
-       memset(&ifr, 0, sizeof(ifr));
-       ifr.ifr_ifindex = index;
-
-       if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
-               close(sk);
-               return -1;
-       }
-
-       DBG("ifname %s", ifr.ifr_name);
-
-       memset(&rt, 0, sizeof(rt));
-       rt.rt_flags = RTF_UP;
-
-       memset(&addr, 0, sizeof(addr));
-       addr.sin6_family = AF_INET6;
-       addr.sin6_addr = any;
-
-       memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
-       memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
-       memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
-
-       rt.rt_dev = ifr.ifr_name;
-
-       err = ioctl(sk, SIOCADDRT, &rt);
-       if (err < 0)
-               connman_error("Setting default interface route failed (%s)",
-                                                       strerror(errno));
-       close(sk);
+                                                       strerror(-err));
 
        return err;
 }
@@ -925,20 +937,23 @@ int connman_inet_clear_gateway_address(int index, const char *gateway)
        struct ifreq ifr;
        struct rtentry rt;
        struct sockaddr_in addr;
-       int sk, err;
+       int sk, err = 0;
 
        DBG("index %d gateway %s", index, gateway);
 
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-       if (sk < 0)
-               return -1;
+       if (sk < 0) {
+               err = -errno;
+               goto out;
+       }
 
        memset(&ifr, 0, sizeof(ifr));
        ifr.ifr_ifindex = index;
 
        if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+               err = -errno;
                close(sk);
-               return -1;
+               goto out;
        }
 
        DBG("ifname %s", ifr.ifr_name);
@@ -961,13 +976,16 @@ int connman_inet_clear_gateway_address(int index, const char *gateway)
        addr.sin_addr.s_addr = INADDR_ANY;
        memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
 
-       err = ioctl(sk, SIOCDELRT, &rt);
-       if (err < 0)
-               connman_error("Removing default gateway route failed (%s)",
-                                                       strerror(errno));
+       if (ioctl(sk, SIOCDELRT, &rt) < 0 && errno != ESRCH)
+               err = -errno;
 
        close(sk);
 
+out:
+       if (err < 0)
+               connman_error("Removing default gateway route failed (%s)",
+                                                       strerror(-err));
+
        return err;
 }
 
@@ -976,20 +994,23 @@ int connman_inet_clear_gateway_interface(int index)
        struct ifreq ifr;
        struct rtentry rt;
        struct sockaddr_in addr;
-       int sk, err;
+       int sk, err = 0;
 
        DBG("index %d", index);
 
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-       if (sk < 0)
-               return -1;
+       if (sk < 0) {
+               err = -errno;
+               goto out;
+       }
 
        memset(&ifr, 0, sizeof(ifr));
        ifr.ifr_ifindex = index;
 
        if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+               err = -errno;
                close(sk);
-               return -1;
+               goto out;
        }
 
        DBG("ifname %s", ifr.ifr_name);
@@ -1007,11 +1028,15 @@ int connman_inet_clear_gateway_interface(int index)
 
        rt.rt_dev = ifr.ifr_name;
 
-       err = ioctl(sk, SIOCDELRT, &rt);
+       if (ioctl(sk, SIOCDELRT, &rt) < 0 && errno != ESRCH)
+               err = -errno;
+
+       close(sk);
+
+out:
        if (err < 0)
                connman_error("Removing default interface route failed (%s)",
-                                                       strerror(errno));
-       close(sk);
+                                                       strerror(-err));
 
        return err;
 }
@@ -1022,20 +1047,23 @@ int connman_inet_clear_ipv6_gateway_interface(int index)
        struct rtentry rt;
        struct sockaddr_in6 addr;
        const struct in6_addr any = IN6ADDR_ANY_INIT;
-       int sk, err;
+       int sk, err = 0;
 
        DBG("index %d", index);
 
        sk = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-       if (sk < 0)
-               return -1;
+       if (sk < 0) {
+               err = -errno;
+               goto out;
+       }
 
        memset(&ifr, 0, sizeof(ifr));
        ifr.ifr_ifindex = index;
 
        if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+               err = -errno;
                close(sk);
-               return -1;
+               goto out;
        }
 
        DBG("ifname %s", ifr.ifr_name);
@@ -1053,16 +1081,20 @@ int connman_inet_clear_ipv6_gateway_interface(int index)
 
        rt.rt_dev = ifr.ifr_name;
 
-       err = ioctl(sk, SIOCDELRT, &rt);
+       if (ioctl(sk, SIOCDELRT, &rt) < 0 && errno != ESRCH)
+               err = -errno;
+
+       close(sk);
+
+out:
        if (err < 0)
                connman_error("Removing default interface route failed (%s)",
-                                                       strerror(errno));
-       close(sk);
+                                                       strerror(-err));
 
        return err;
 }
 
-connman_bool_t connman_inet_compare_subnet(int index, const char *host)
+bool connman_inet_compare_subnet(int index, const char *host)
 {
        struct ifreq ifr;
        struct in_addr _host_addr;
@@ -1072,8 +1104,8 @@ connman_bool_t connman_inet_compare_subnet(int index, const char *host)
 
        DBG("host %s", host);
 
-       if (host == NULL)
-               return FALSE;
+       if (!host)
+               return false;
 
        if (inet_aton(host, &_host_addr) == 0)
                return -1;
@@ -1081,19 +1113,19 @@ connman_bool_t connman_inet_compare_subnet(int index, const char *host)
 
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0)
-               return FALSE;
+               return false;
 
        memset(&ifr, 0, sizeof(ifr));
        ifr.ifr_ifindex = index;
 
        if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
                close(sk);
-               return FALSE;
+               return false;
        }
 
        if (ioctl(sk, SIOCGIFNETMASK, &ifr) < 0) {
                close(sk);
-               return FALSE;
+               return false;
        }
 
        netmask = (struct sockaddr_in *)&ifr.ifr_netmask;
@@ -1101,7 +1133,7 @@ connman_bool_t connman_inet_compare_subnet(int index, const char *host)
 
        if (ioctl(sk, SIOCGIFADDR, &ifr) < 0) {
                close(sk);
-               return FALSE;
+               return false;
        }
 
        close(sk);
@@ -1115,59 +1147,63 @@ connman_bool_t connman_inet_compare_subnet(int index, const char *host)
 int connman_inet_remove_from_bridge(int index, const char *bridge)
 {
        struct ifreq ifr;
-       int sk, err;
+       int sk, err = 0;
 
-       if (bridge == NULL)
+       if (!bridge)
                return -EINVAL;
 
        sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
-       if (sk < 0)
-               return sk;
+       if (sk < 0) {
+               err = -errno;
+               goto out;
+       }
 
        memset(&ifr, 0, sizeof(ifr));
-       strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
+       strncpy(ifr.ifr_name, bridge, sizeof(ifr.ifr_name) - 1);
        ifr.ifr_ifindex = index;
 
-       err = ioctl(sk, SIOCBRDELIF, &ifr);
+       if (ioctl(sk, SIOCBRDELIF, &ifr) < 0)
+               err = -errno;
 
        close(sk);
 
-       if (err < 0) {
+out:
+       if (err < 0)
                connman_error("Remove interface from bridge error %s",
-                                                       strerror(errno));
-               return err;
-       }
+                                                       strerror(-err));
 
-       return 0;
+       return err;
 }
 
 int connman_inet_add_to_bridge(int index, const char *bridge)
 {
        struct ifreq ifr;
-       int sk, err;
+       int sk, err = 0;
 
-       if (bridge == NULL)
+       if (!bridge)
                return -EINVAL;
 
        sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
-       if (sk < 0)
-               return sk;
+       if (sk < 0) {
+               err = -errno;
+               goto out;
+       }
 
        memset(&ifr, 0, sizeof(ifr));
-       strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
+       strncpy(ifr.ifr_name, bridge, sizeof(ifr.ifr_name) - 1);
        ifr.ifr_ifindex = index;
 
-       err = ioctl(sk, SIOCBRADDIF, &ifr);
+       if (ioctl(sk, SIOCBRADDIF, &ifr) < 0)
+               err = -errno;
 
        close(sk);
 
-       if (err < 0) {
+out:
+       if (err < 0)
                connman_error("Add interface to bridge error %s",
-                                                       strerror(errno));
-               return err;
-       }
+                                                       strerror(-err));
 
-       return 0;
+       return err;
 }
 
 int connman_inet_set_mtu(int index, int mtu)
@@ -1199,7 +1235,7 @@ int connman_inet_setup_tunnel(char *tunnel, int mtu)
        __u32 mask;
        __u32 flags;
 
-       if (tunnel == NULL)
+       if (!tunnel)
                return -EINVAL;
 
        sk = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
@@ -1213,7 +1249,7 @@ int connman_inet_setup_tunnel(char *tunnel, int mtu)
                goto done;
 
        memset(&ifr, 0, sizeof(ifr));
-       strncpy(ifr.ifr_name, tunnel, IFNAMSIZ);
+       strncpy(ifr.ifr_name, tunnel, sizeof(ifr.ifr_name) - 1);
        err = ioctl(sk, SIOCGIFFLAGS, &ifr);
        if (err)
                goto done;
@@ -1269,11 +1305,15 @@ int connman_inet_create_tunnel(char **iface)
        return fd;
 }
 
-struct rs_cb_data {
+/*
+ * This callback struct is used when sending router and neighbor
+ * solicitation and advertisement messages.
+ */
+struct xs_cb_data {
        GIOChannel *channel;
-       __connman_inet_rs_cb_t callback;
+       void *callback;
        struct sockaddr_in6 addr;
-       guint rs_timeout;
+       guint timeout;
        guint watch_id;
        void *user_data;
 };
@@ -1288,16 +1328,16 @@ static const struct in6_addr in6addr_all_nodes_mc = IN6ADDR_ALL_NODES_MC_INIT;
 static const struct in6_addr in6addr_all_routers_mc =
                                                IN6ADDR_ALL_ROUTERS_MC_INIT;
 
-static void rs_cleanup(struct rs_cb_data *data)
+static void xs_cleanup(struct xs_cb_data *data)
 {
-       if (data->channel != NULL) {
+       if (data->channel) {
                g_io_channel_shutdown(data->channel, TRUE, NULL);
                g_io_channel_unref(data->channel);
                data->channel = NULL;
        }
 
-       if (data->rs_timeout > 0)
-               g_source_remove(data->rs_timeout);
+       if (data->timeout > 0)
+               g_source_remove(data->timeout);
 
        if (data->watch_id > 0)
                g_source_remove(data->watch_id);
@@ -1307,31 +1347,33 @@ static void rs_cleanup(struct rs_cb_data *data)
 
 static gboolean rs_timeout_cb(gpointer user_data)
 {
-       struct rs_cb_data *data = user_data;
+       struct xs_cb_data *data = user_data;
 
        DBG("user data %p", user_data);
 
-       if (data == NULL)
+       if (!data)
                return FALSE;
 
-       if (data->callback != NULL)
-               data->callback(NULL, 0, data->user_data);
+       if (data->callback) {
+               __connman_inet_rs_cb_t cb = data->callback;
+               cb(NULL, 0, data->user_data);
+       }
 
-       data->rs_timeout = 0;
-       rs_cleanup(data);
+       data->timeout = 0;
+       xs_cleanup(data);
        return FALSE;
 }
 
-static int icmpv6_recv(int fd, gpointer user_data)
+static int icmpv6_recv(int fd, struct xs_cb_data *data)
 {
        struct msghdr mhdr;
        struct iovec iov;
        unsigned char chdr[CMSG_BUF_LEN];
        unsigned char buf[1540];
-       struct rs_cb_data *data = user_data;
        struct nd_router_advert *hdr;
        struct sockaddr_in6 saddr;
        ssize_t len;
+       __connman_inet_rs_cb_t cb = data->callback;
 
        DBG("");
 
@@ -1340,6 +1382,7 @@ static int icmpv6_recv(int fd, gpointer user_data)
 
        mhdr.msg_name = (void *)&saddr;
        mhdr.msg_namelen = sizeof(struct sockaddr_in6);
+       mhdr.msg_flags = 0;
        mhdr.msg_iov = &iov;
        mhdr.msg_iovlen = 1;
        mhdr.msg_control = (void *)chdr;
@@ -1347,43 +1390,74 @@ static int icmpv6_recv(int fd, gpointer user_data)
 
        len = recvmsg(fd, &mhdr, 0);
        if (len < 0) {
-               data->callback(NULL, 0, data->user_data);
-               rs_cleanup(data);
+               cb(NULL, 0, data->user_data);
                return -errno;
        }
 
+#if defined TIZEN_EXT
+       /* Set Received Source Address from router as IPv6 Gateway Address */
+       char src_addr[INET6_ADDRSTRLEN];
+       if(inet_ntop(AF_INET6, &(saddr.sin6_addr), src_addr, INET6_ADDRSTRLEN)
+                       == NULL)
+               return -errno;
+
+       DBG("Received Source Address %s from router", src_addr);
+
+       /* icmpv6_recv() function can be called in two scenarios :
+        * 1. When __connman_inet_ipv6_send_rs() is called from check_dhcpv6()
+        * 2. When __connman_inet_ipv6_send_rs() is called from
+        * __connman_6to4_probe()
+        * In the second case it is not  required to set DHCPv6 Gateway  Address
+        * as DHCPv6 was not started and  network structure was not passed as
+        * user_data. If it is tried  to add Source Address as  Gateway Address
+        * then it will lead to  crash because of  user_data being ip_address
+        * instead of network structure. So Adding Gateway Address in case 1st
+        * case only.
+        */
+       char *address = data->user_data;
+       int err = 0;
+       unsigned char buffer[sizeof(struct in6_addr)] = {0, };
+       /* Checking if user_data is an ip_address */
+       err = inet_pton(AF_INET, address, buffer);
+       /* Setting Received Source Address from
+        * router as Gateway Address */
+       if(err <= 0)
+               __connman_network_set_auto_ipv6_gateway(src_addr, data->user_data);
+#endif
        hdr = (struct nd_router_advert *)buf;
        DBG("code %d len %zd hdr %zd", hdr->nd_ra_code, len,
                                sizeof(struct nd_router_advert));
        if (hdr->nd_ra_code != 0)
                return 0;
 
-       data->callback(hdr, len, data->user_data);
-       rs_cleanup(data);
+       cb(hdr, len, data->user_data);
 
        return len;
 }
 
-static gboolean icmpv6_event(GIOChannel *chan, GIOCondition cond,
-                                                               gpointer data)
+static gboolean icmpv6_event(GIOChannel *chan, GIOCondition cond, gpointer data)
 {
        int fd, ret;
+       struct xs_cb_data *xs_data = data;
 
        DBG("");
 
        if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
-               return FALSE;
+               goto cleanup;
 
        fd = g_io_channel_unix_get_fd(chan);
-       ret = icmpv6_recv(fd, data);
+       ret = icmpv6_recv(fd, xs_data);
        if (ret == 0)
                return TRUE;
 
-       return FALSE;
+cleanup:
+       xs_cleanup(xs_data);
+       return TRUE;
 }
 
 /* Adapted from RFC 1071 "C" Implementation Example */
-static uint16_t csum(const void *phdr, const void *data, socklen_t datalen)
+static uint16_t csum(const void *phdr, const void *data, socklen_t datalen,
+               const void *extra_data, socklen_t extra_datalen)
 {
        register unsigned long sum = 0;
        socklen_t count;
@@ -1404,13 +1478,25 @@ static uint16_t csum(const void *phdr, const void *data, socklen_t datalen)
                count -= 2;
        }
 
+       if (extra_data) {
+               count = extra_datalen;
+               addr = (uint16_t *)extra_data;
+
+               while (count > 1) {
+                       sum += *(addr++);
+                       count -= 2;
+               }
+       }
+
        while (sum >> 16)
                sum = (sum & 0xffff) + (sum >> 16);
 
        return (uint16_t)~sum;
 }
 
-static int ndisc_send_unspec(int type, int oif, const struct in6_addr *dest)
+static int ndisc_send_unspec(int type, int oif, const struct in6_addr *dest,
+                       const struct in6_addr *source,
+                       unsigned char *buf, size_t len, uint16_t lifetime)
 {
        struct _phdr {
                struct in6_addr src;
@@ -1426,16 +1512,20 @@ static int ndisc_send_unspec(int type, int oif, const struct in6_addr *dest)
                        struct icmp6_hdr icmp;
                        struct nd_neighbor_solicit ns;
                        struct nd_router_solicit rs;
+                       struct nd_router_advert ra;
                } i;
        } frame;
 
        struct msghdr msgh;
        struct cmsghdr *cmsg;
        struct in6_pktinfo *pinfo;
-       struct sockaddr_in6 dst;
+       struct sockaddr_in6 dst, src;
        char cbuf[CMSG_SPACE(sizeof(*pinfo))];
-       struct iovec iov;
-       int fd, datalen, ret;
+       struct iovec iov[2];
+       int fd, datalen, ret, iovlen = 1;
+#if defined TIZEN_EXT
+       char ebuf[256];
+#endif
 
        DBG("");
 
@@ -1446,35 +1536,60 @@ static int ndisc_send_unspec(int type, int oif, const struct in6_addr *dest)
        memset(&frame, 0, sizeof(frame));
        memset(&dst, 0, sizeof(dst));
 
-       datalen = sizeof(frame.i.rs); /* 8, csum() safe */
+       if (type == ND_ROUTER_SOLICIT)
+               datalen = sizeof(frame.i.rs); /* 8, csum() safe */
+       else if (type == ND_ROUTER_ADVERT) {
+               datalen = sizeof(frame.i.ra); /* 16, csum() safe */
+               frame.i.ra.nd_ra_router_lifetime = htons(lifetime);
+       } else if (type == ND_NEIGHBOR_SOLICIT) {
+               datalen = sizeof(frame.i.ns); /* 24, csum() safe */
+               memcpy(&frame.i.ns.nd_ns_target, buf, sizeof(struct in6_addr));
+       } else {
+               close(fd);
+               return -EINVAL;
+       }
+
        dst.sin6_addr = *dest;
 
+       if (source)
+               src.sin6_addr = *source;
+       else
+               src.sin6_addr = in6addr_any;
+
        /* Fill in the IPv6 header */
        frame.ip.ip6_vfc = 0x60;
-       frame.ip.ip6_plen = htons(datalen);
+       frame.ip.ip6_plen = htons(datalen + len);
        frame.ip.ip6_nxt = IPPROTO_ICMPV6;
        frame.ip.ip6_hlim = 255;
        frame.ip.ip6_dst = dst.sin6_addr;
+       frame.ip.ip6_src = src.sin6_addr;
        /* all other fields are already set to zero */
 
        /* Prepare pseudo header for csum */
        memset(&phdr, 0, sizeof(phdr));
        phdr.dst = dst.sin6_addr;
-       phdr.plen = htonl(datalen);
+       phdr.src = src.sin6_addr;
+       phdr.plen = htonl(datalen + len);
        phdr.nxt = IPPROTO_ICMPV6;
 
        /* Fill in remaining ICMP header fields */
        frame.i.icmp.icmp6_type = type;
-       frame.i.icmp.icmp6_cksum = csum(&phdr, &frame.i, datalen);
+       frame.i.icmp.icmp6_cksum = csum(&phdr, &frame.i, datalen, buf, len);
 
-       iov.iov_base = &frame;
-       iov.iov_len = sizeof(frame.ip) + datalen;
+       iov[0].iov_base = &frame;
+       iov[0].iov_len = sizeof(frame.ip) + datalen;
+
+       if (buf) {
+               iov[1].iov_base = buf;
+               iov[1].iov_len = len;
+               iovlen = 2;
+       }
 
        dst.sin6_family = AF_INET6;
        msgh.msg_name = &dst;
        msgh.msg_namelen = sizeof(dst);
-       msgh.msg_iov = &iov;
-       msgh.msg_iovlen = 1;
+       msgh.msg_iov = iov;
+       msgh.msg_iovlen = iovlen;
        msgh.msg_flags = 0;
 
        memset(cbuf, 0, CMSG_SPACE(sizeof(*pinfo)));
@@ -1489,6 +1604,9 @@ static int ndisc_send_unspec(int type, int oif, const struct in6_addr *dest)
        msgh.msg_controllen = cmsg->cmsg_len;
 
        ret = sendmsg(fd, &msgh, 0);
+#if defined TIZEN_EXT
+       DBG("sendmsg errno: %d/%s", errno, strerror_r(errno, ebuf, sizeof(ebuf)));
+#endif
 
        close(fd);
        return ret;
@@ -1524,46 +1642,441 @@ static int if_mc_group(int sock, int ifindex, const struct in6_addr *mc_addr,
 
        ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
                        &val, sizeof(int));
+       if (ret < 0) {
+               ret = -errno;
+               DBG("Cannot set IPV6_MULTICAST_LOOP %d/%s", ret,
+                       strerror(-ret));
+               return ret;
+       }
 
-       if (ret < 0)
+       ret = setsockopt(sock, IPPROTO_IPV6, cmd, &mreq, sizeof(mreq));
+       if (ret < 0) {
+               ret = -errno;
+               DBG("Cannot set option %d %d/%s", cmd, ret, strerror(-ret));
                return ret;
+       }
 
-       return setsockopt(sock, IPPROTO_IPV6, cmd, &mreq, sizeof(mreq));
+       return 0;
 }
 
 int __connman_inet_ipv6_send_rs(int index, int timeout,
                        __connman_inet_rs_cb_t callback, void *user_data)
 {
-       struct rs_cb_data *data;
+       struct xs_cb_data *data;
        struct icmp6_filter filter;
        struct in6_addr solicit;
        struct in6_addr dst = in6addr_all_routers_mc;
        int sk;
 
+       if (timeout <= 0)
+               return -EINVAL;
+
+       data = g_try_malloc0(sizeof(struct xs_cb_data));
+       if (!data)
+               return -ENOMEM;
+
+       data->callback = callback;
+       data->user_data = user_data;
+       data->timeout = g_timeout_add_seconds(timeout, rs_timeout_cb, data);
+
+       sk = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_ICMPV6);
+       if (sk < 0)
+               return -errno;
+
+       DBG("sock %d", sk);
+
+       ICMP6_FILTER_SETBLOCKALL(&filter);
+       ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
+
+       setsockopt(sk, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
+                                               sizeof(struct icmp6_filter));
+
+       ipv6_addr_solict_mult(&dst, &solicit);
+       if_mc_group(sk, index, &in6addr_all_nodes_mc, IPV6_JOIN_GROUP);
+       if_mc_group(sk, index, &solicit, IPV6_JOIN_GROUP);
+
+       data->channel = g_io_channel_unix_new(sk);
+       g_io_channel_set_close_on_unref(data->channel, TRUE);
+
+       g_io_channel_set_encoding(data->channel, NULL, NULL);
+       g_io_channel_set_buffered(data->channel, FALSE);
+
+       data->watch_id = g_io_add_watch(data->channel,
+                       G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+                       icmpv6_event, data);
+
+       ndisc_send_unspec(ND_ROUTER_SOLICIT, index, &dst, NULL, NULL, 0, 0);
+
+       return 0;
+}
+
+static inline void ipv6_addr_advert_mult(const struct in6_addr *addr,
+                                       struct in6_addr *advert)
+{
+       ipv6_addr_set(advert, htonl(0xFF020000), 0, htonl(0x2),
+                       htonl(0xFF000000) | addr->s6_addr32[3]);
+}
+
+#define MSG_SIZE_SEND 1452
+
+static int inc_len(int len, int inc)
+{
+       if (len > MSG_SIZE_SEND)
+               return -EINVAL;
+
+       len += inc;
+       return len;
+}
+
+int __connman_inet_ipv6_send_ra(int index, struct in6_addr *src_addr,
+                               GSList *prefixes, int router_lifetime)
+{
+       GSList *list;
+       struct in6_addr src, *source;
+       struct in6_addr dst = in6addr_all_nodes_mc;
+       GDHCPIAPrefix *prefix;
+       unsigned char buf[MSG_SIZE_SEND];
+       char addr_str[INET6_ADDRSTRLEN];
+       int sk, err = 0;
+       int len, count = 0;
+
+       if (!prefixes)
+               return -EINVAL;
+
+       sk = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_ICMPV6);
+       if (sk < 0)
+               return -errno;
+
+       if (!src_addr) {
+               __connman_inet_get_interface_ll_address(index, AF_INET6, &src);
+               source = &src;
+       } else
+               source = src_addr;
+
+       DBG("sock %d index %d prefixes %p src %s lifetime %d", sk, index,
+               prefixes, inet_ntop(AF_INET6, source, addr_str,
+                               INET6_ADDRSTRLEN),
+               router_lifetime);
+
+       memset(buf, 0, MSG_SIZE_SEND);
+       len = 0;
+
+       for (list = prefixes; list; list = list->next) {
+               struct nd_opt_prefix_info *pinfo;
+
+               prefix = list->data;
+               pinfo = (struct nd_opt_prefix_info *)(buf + len);
+
+               len = inc_len(len, sizeof(*pinfo));
+               if (len < 0) {
+                       err = len;
+                       goto out;
+               }
+
+               pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
+               pinfo->nd_opt_pi_len = 4;
+               pinfo->nd_opt_pi_prefix_len = prefix->prefixlen;
+               pinfo->nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_ONLINK;
+               pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
+               if (router_lifetime > 0) {
+                       pinfo->nd_opt_pi_valid_time = htonl(prefix->valid);
+                       pinfo->nd_opt_pi_preferred_time =
+                                               htonl(prefix->preferred);
+               }
+               pinfo->nd_opt_pi_reserved2 = 0;
+
+               memcpy(&pinfo->nd_opt_pi_prefix, &prefix->prefix,
+                                               sizeof(struct in6_addr));
+
+               DBG("[%d] index %d prefix %s/%d", count, index,
+                       inet_ntop(AF_INET6, &prefix->prefix, addr_str,
+                               INET6_ADDRSTRLEN), prefix->prefixlen);
+
+               count++;
+       }
+
+       if (count > 0) {
+               err = ndisc_send_unspec(ND_ROUTER_ADVERT, index, &dst, source,
+                                       buf, len, router_lifetime);
+               if (err < 0)
+                       DBG("cannot send RA %d/%s", err, strerror(-err));
+       }
+
+out:
+       close(sk);
+       return err;
+}
+
+void __connman_inet_ipv6_stop_recv_rs(void *context)
+{
+       if (!context)
+               return;
+
+       xs_cleanup(context);
+}
+
+static int icmpv6_rs_recv(int fd, struct xs_cb_data *data)
+{
+       struct msghdr mhdr;
+       struct iovec iov;
+       unsigned char chdr[CMSG_BUF_LEN];
+       unsigned char buf[1540];
+       struct nd_router_solicit *hdr;
+       struct sockaddr_in6 saddr;
+       ssize_t len;
+       __connman_inet_recv_rs_cb_t cb = data->callback;
+
        DBG("");
 
-       if (timeout <= 0)
+       iov.iov_len = sizeof(buf);
+       iov.iov_base = buf;
+
+       mhdr.msg_name = (void *)&saddr;
+       mhdr.msg_namelen = sizeof(struct sockaddr_in6);
+       mhdr.msg_flags = 0;
+       mhdr.msg_iov = &iov;
+       mhdr.msg_iovlen = 1;
+       mhdr.msg_control = (void *)chdr;
+       mhdr.msg_controllen = CMSG_BUF_LEN;
+
+       len = recvmsg(fd, &mhdr, 0);
+       if (len < 0) {
+               cb(NULL, 0, data->user_data);
+               return -errno;
+       }
+
+       hdr = (struct nd_router_solicit *)buf;
+       DBG("code %d len %zd hdr %zd", hdr->nd_rs_code, len,
+                               sizeof(struct nd_router_solicit));
+       if (hdr->nd_rs_code != 0)
+               return 0;
+
+       cb(hdr, len, data->user_data);
+       return len;
+}
+
+static gboolean icmpv6_rs_event(GIOChannel *chan, GIOCondition cond,
+                                                               gpointer data)
+{
+       int fd, ret;
+       struct xs_cb_data *xs_data = data;
+
+       DBG("");
+
+       if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
+               goto cleanup;
+
+       fd = g_io_channel_unix_get_fd(chan);
+       ret = icmpv6_rs_recv(fd, xs_data);
+       if (ret == 0)
+               return TRUE;
+
+cleanup:
+       xs_data->watch_id = 0;
+       return FALSE;
+}
+
+int __connman_inet_ipv6_start_recv_rs(int index,
+                                       __connman_inet_recv_rs_cb_t callback,
+                                       void *user_data,
+                                       void **context)
+{
+       struct xs_cb_data *data;
+       struct icmp6_filter filter;
+       char addr_str[INET6_ADDRSTRLEN];
+       int sk, err;
+
+       data = g_try_malloc0(sizeof(struct xs_cb_data));
+       if (!data)
+               return -ENOMEM;
+
+       data->callback = callback;
+       data->user_data = user_data;
+
+       sk = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_ICMPV6);
+       if (sk < 0) {
+               g_free(data);
+               return -errno;
+       }
+
+       DBG("sock %d", sk);
+
+       ICMP6_FILTER_SETBLOCKALL(&filter);
+       ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
+
+       setsockopt(sk, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
+                                               sizeof(struct icmp6_filter));
+
+       err = if_mc_group(sk, index, &in6addr_all_routers_mc, IPV6_JOIN_GROUP);
+       if (err < 0)
+               DBG("Cannot join mc %s %d/%s", inet_ntop(AF_INET6,
+                       &in6addr_all_routers_mc, addr_str, INET6_ADDRSTRLEN),
+                       err, strerror(-err));
+
+       data->channel = g_io_channel_unix_new(sk);
+       g_io_channel_set_close_on_unref(data->channel, TRUE);
+
+       g_io_channel_set_encoding(data->channel, NULL, NULL);
+       g_io_channel_set_buffered(data->channel, FALSE);
+
+       data->watch_id = g_io_add_watch(data->channel,
+                       G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+                       icmpv6_rs_event, data);
+
+       *context = data;
+
+       return 0;
+}
+
+static gboolean ns_timeout_cb(gpointer user_data)
+{
+       struct xs_cb_data *data = user_data;
+
+       DBG("user data %p", user_data);
+
+       if (!data)
+               return FALSE;
+
+       if (data->callback) {
+               __connman_inet_ns_cb_t cb = data->callback;
+               cb(NULL, 0, &data->addr.sin6_addr, data->user_data);
+       }
+
+       data->timeout = 0;
+       xs_cleanup(data);
+       return FALSE;
+}
+
+static int icmpv6_nd_recv(int fd, struct xs_cb_data *data)
+{
+       struct msghdr mhdr;
+       struct iovec iov;
+       unsigned char chdr[CMSG_BUF_LEN];
+       unsigned char buf[1540];
+       struct nd_neighbor_advert *hdr;
+       struct sockaddr_in6 saddr;
+       ssize_t len;
+       __connman_inet_ns_cb_t cb = data->callback;
+
+       DBG("");
+
+       iov.iov_len = sizeof(buf);
+       iov.iov_base = buf;
+
+       mhdr.msg_name = (void *)&saddr;
+       mhdr.msg_namelen = sizeof(struct sockaddr_in6);
+       mhdr.msg_flags = 0;
+       mhdr.msg_iov = &iov;
+       mhdr.msg_iovlen = 1;
+       mhdr.msg_control = (void *)chdr;
+       mhdr.msg_controllen = CMSG_BUF_LEN;
+
+       len = recvmsg(fd, &mhdr, 0);
+       if (len < 0) {
+               cb(NULL, 0, &data->addr.sin6_addr, data->user_data);
+               return -errno;
+       }
+
+       hdr = (struct nd_neighbor_advert *)buf;
+       DBG("code %d len %zd hdr %zd", hdr->nd_na_code, len,
+                               sizeof(struct nd_neighbor_advert));
+       if (hdr->nd_na_code != 0)
+               return 0;
+
+       /*
+        * We can receive any neighbor advertisement so we need to check if the
+        * packet was meant for us and ignore the packet otherwise.
+        */
+       if (memcmp(&data->addr.sin6_addr, &hdr->nd_na_target,
+                       sizeof(struct in6_addr)))
+               return 0;
+
+       cb(hdr, len, &data->addr.sin6_addr, data->user_data);
+
+       return len;
+}
+
+static gboolean icmpv6_nd_event(GIOChannel *chan, GIOCondition cond,
+                                                               gpointer data)
+{
+       int fd, ret;
+       struct xs_cb_data *xs_data = data;
+
+       DBG("");
+
+       if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
+               goto cleanup;
+
+       fd = g_io_channel_unix_get_fd(chan);
+       ret = icmpv6_nd_recv(fd, xs_data);
+       if (ret == 0)
+               return TRUE;
+
+cleanup:
+       xs_cleanup(xs_data);
+       return TRUE;
+}
+
+int __connman_inet_ipv6_do_dad(int index, int timeout_ms,
+                               struct in6_addr *addr,
+                               __connman_inet_ns_cb_t callback,
+                               void *user_data)
+{
+       struct xs_cb_data *data;
+       struct icmp6_filter filter;
+       struct in6_addr solicit;
+       int sk, err, val = 1;
+
+       if (timeout_ms <= 0)
                return -EINVAL;
 
-       data = g_try_malloc0(sizeof(struct rs_cb_data));
-       if (data == NULL)
+       data = g_try_malloc0(sizeof(struct xs_cb_data));
+       if (!data)
                return -ENOMEM;
 
        data->callback = callback;
        data->user_data = user_data;
-       data->rs_timeout = g_timeout_add_seconds(timeout, rs_timeout_cb, data);
+       data->timeout = g_timeout_add_full(G_PRIORITY_DEFAULT,
+                                       (guint)timeout_ms,
+                                       ns_timeout_cb,
+                                       data,
+                                        NULL);
+       memcpy(&data->addr.sin6_addr, addr, sizeof(struct in6_addr));
 
        sk = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_ICMPV6);
        if (sk < 0)
                return -errno;
 
-       ICMP6_FILTER_SETBLOCKALL(&filter);
-       ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
+       DBG("sock %d", sk);
+
+       ICMP6_FILTER_SETBLOCKALL(&filter);
+       ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filter);
+
+       setsockopt(sk, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
+                                               sizeof(struct icmp6_filter));
+
+        if (setsockopt(sk, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+                                               &val, sizeof(val)) < 0) {
+               err = -errno;
+                DBG("Cannot set IPV6_RECVPKTINFO %d/%s", err,
+                                                       strerror(-err));
+               close(sk);
+               return err;
+        }
+
+        if (setsockopt(sk, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
+                                               &val, sizeof(val)) < 0) {
+               err = -errno;
+                DBG("Cannot set IPV6_RECVHOPLIMIT %d/%s", err,
+                                                       strerror(-err));
+               close(sk);
+               return err;
+        }
 
-       setsockopt(sk, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
-                                               sizeof(struct icmp6_filter));
+       val = 0;
+       setsockopt(sk, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, sizeof(val));
 
-       ipv6_addr_solict_mult(&dst, &solicit);
+       ipv6_addr_solict_mult(addr, &solicit);
        if_mc_group(sk, index, &in6addr_all_nodes_mc, IPV6_JOIN_GROUP);
        if_mc_group(sk, index, &solicit, IPV6_JOIN_GROUP);
 
@@ -1575,11 +2088,16 @@ int __connman_inet_ipv6_send_rs(int index, int timeout,
 
        data->watch_id = g_io_add_watch(data->channel,
                        G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
-                       icmpv6_event, data);
+                       icmpv6_nd_event, data);
 
-       ndisc_send_unspec(ND_ROUTER_SOLICIT, index, &dst);
+       err = ndisc_send_unspec(ND_NEIGHBOR_SOLICIT, index, &solicit, NULL,
+                       (unsigned char *)addr, 0, 0);
+       if (err < 0) {
+               DBG("Cannot send NS %d/%s", err, strerror(-err));
+               xs_cleanup(data);
+       }
 
-       return 0;
+       return err;
 }
 
 GSList *__connman_inet_ipv6_get_prefixes(struct nd_router_advert *hdr,
@@ -1613,7 +2131,7 @@ GSList *__connman_inet_ipv6_get_prefixes(struct nd_router_advert *hdr,
                        pinfo = (struct nd_opt_prefix_info *)pos;
                        prefix = inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
                                        prefix_str, INET6_ADDRSTRLEN);
-                       if (prefix == NULL)
+                       if (!prefix)
                                break;
 
                        str = g_strdup_printf("%s/%d", prefix,
@@ -1686,7 +2204,7 @@ static int get_dest_addr(int family, int index, char *buf, int len)
                return -errno;
        }
 
-       if (inet_ntop(family, addr, buf, len) == NULL) {
+       if (!inet_ntop(family, addr, buf, len)) {
                DBG("error %d/%s", errno, strerror(errno));
                return -errno;
        }
@@ -1781,7 +2299,7 @@ static void inet_rtnl_cleanup(struct inet_rtnl_cb_data *data)
 {
        struct __connman_inet_rtnl_handle *rth = data->rtnl;
 
-       if (data->channel != NULL) {
+       if (data->channel) {
                g_io_channel_shutdown(data->channel, TRUE, NULL);
                g_io_channel_unref(data->channel);
                data->channel = NULL;
@@ -1795,7 +2313,7 @@ static void inet_rtnl_cleanup(struct inet_rtnl_cb_data *data)
        if (data->watch_id > 0)
                g_source_remove(data->watch_id);
 
-       if (rth != NULL) {
+       if (rth) {
                __connman_inet_rtnl_close(rth);
                g_free(rth);
        }
@@ -1809,10 +2327,10 @@ static gboolean inet_rtnl_timeout_cb(gpointer user_data)
 
        DBG("user data %p", user_data);
 
-       if (data == NULL)
+       if (!data)
                return FALSE;
 
-       if (data->callback != NULL)
+       if (data->callback)
                data->callback(NULL, data->user_data);
 
        data->rtnl_timeout = 0;
@@ -1820,9 +2338,8 @@ static gboolean inet_rtnl_timeout_cb(gpointer user_data)
        return FALSE;
 }
 
-static int inet_rtnl_recv(GIOChannel *chan, gpointer user_data)
+static int inet_rtnl_recv(GIOChannel *chan, struct inet_rtnl_cb_data *rtnl_data)
 {
-       struct inet_rtnl_cb_data *rtnl_data = user_data;
        struct __connman_inet_rtnl_handle *rth = rtnl_data->rtnl;
        struct nlmsghdr *h = NULL;
        struct sockaddr_nl nladdr;
@@ -1861,10 +2378,8 @@ static int inet_rtnl_recv(GIOChannel *chan, gpointer user_data)
 
                h = ptr;
 
-               if (!NLMSG_OK(h, len)) {
+               if (!NLMSG_OK(h, len))
                        return -1;
-                       break;
-               }
 
                if (h->nlmsg_seq != rth->seq) {
                        /* Skip this msg */
@@ -1906,17 +2421,20 @@ static gboolean inet_rtnl_event(GIOChannel *chan, GIOCondition cond,
                                                        gpointer user_data)
 {
        int ret;
+       struct inet_rtnl_cb_data *rtnl_data = user_data;
 
        DBG("");
 
        if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
-               return FALSE;
+               goto cleanup;
 
-       ret = inet_rtnl_recv(chan, user_data);
-       if (ret != 0)
+       ret = inet_rtnl_recv(chan, rtnl_data);
+       if (ret == 0)
                return TRUE;
 
-       return FALSE;
+cleanup:
+       inet_rtnl_cleanup(rtnl_data);
+       return TRUE;
 }
 
 int __connman_inet_rtnl_talk(struct __connman_inet_rtnl_handle *rtnl,
@@ -1925,17 +2443,16 @@ int __connman_inet_rtnl_talk(struct __connman_inet_rtnl_handle *rtnl,
 {
        struct sockaddr_nl nladdr;
        struct inet_rtnl_cb_data *data;
-       unsigned seq;
        int err;
 
        memset(&nladdr, 0, sizeof(nladdr));
        nladdr.nl_family = AF_NETLINK;
 
-       n->nlmsg_seq = seq = ++rtnl->seq;
+       n->nlmsg_seq = ++rtnl->seq;
 
-       if (callback != NULL) {
+       if (callback) {
                data = g_try_malloc0(sizeof(struct inet_rtnl_cb_data));
-               if (data == NULL)
+               if (!data)
                        return -ENOMEM;
 
                data->callback = callback;
@@ -1945,7 +2462,6 @@ int __connman_inet_rtnl_talk(struct __connman_inet_rtnl_handle *rtnl,
                                                inet_rtnl_timeout_cb, data);
 
                data->channel = g_io_channel_unix_new(rtnl->fd);
-               g_io_channel_set_close_on_unref(data->channel, TRUE);
 
                g_io_channel_set_encoding(data->channel, NULL, NULL);
                g_io_channel_set_buffered(data->channel, FALSE);
@@ -1958,9 +2474,10 @@ int __connman_inet_rtnl_talk(struct __connman_inet_rtnl_handle *rtnl,
 
        err = sendto(rtnl->fd, &rtnl->req.n, rtnl->req.n.nlmsg_len, 0,
                (struct sockaddr *) &nladdr, sizeof(nladdr));
-       DBG("handle %p len %d err %d", rtnl, rtnl->req.n.nlmsg_len, err);
+       DBG("handle %p len %d", rtnl, rtnl->req.n.nlmsg_len);
        if (err < 0) {
-               connman_error("Can not talk to rtnetlink");
+               connman_error("Can not talk to rtnetlink err %d %s",
+                       -errno, strerror(errno));
                return -errno;
        }
 
@@ -2032,7 +2549,7 @@ static void get_route_cb(struct nlmsghdr *answer, void *user_data)
 
        DBG("answer %p data %p", answer, user_data);
 
-       if (answer == NULL)
+       if (!answer)
                goto out;
 
        len = answer->nlmsg_len;
@@ -2053,10 +2570,10 @@ static void get_route_cb(struct nlmsghdr *answer, void *user_data)
 
        parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
 
-       if (tb[RTA_OIF] != NULL)
+       if (tb[RTA_OIF])
                index = *(int *)RTA_DATA(tb[RTA_OIF]);
 
-       if (tb[RTA_GATEWAY] != NULL)
+       if (tb[RTA_GATEWAY])
                addr = inet_ntop(r->rtm_family,
                                RTA_DATA(tb[RTA_GATEWAY]),
                                abuf, sizeof(abuf));
@@ -2064,7 +2581,7 @@ static void get_route_cb(struct nlmsghdr *answer, void *user_data)
        DBG("addr %s index %d user %p", addr, index, data->user_data);
 
 out:
-       if (data != NULL && data->callback != NULL)
+       if (data && data->callback)
                data->callback(addr, index, data->user_data);
 
        g_free(data);
@@ -2085,7 +2602,7 @@ int __connman_inet_get_route(const char *dest_address,
 
        DBG("dest %s", dest_address);
 
-       if (dest_address == NULL)
+       if (!dest_address)
                return -EINVAL;
 
        memset(&hints, 0, sizeof(hints));
@@ -2097,7 +2614,7 @@ int __connman_inet_get_route(const char *dest_address,
                return -EINVAL;
 
        rth = g_try_malloc0(sizeof(struct __connman_inet_rtnl_handle));
-       if (rth == NULL) {
+       if (!rth) {
                freeaddrinfo(rp);
                return -ENOMEM;
        }
@@ -2124,7 +2641,7 @@ int __connman_inet_get_route(const char *dest_address,
                goto fail;
 
        data = g_try_malloc(sizeof(struct get_route_cb_data));
-       if (data == NULL) {
+       if (!data) {
                err = -ENOMEM;
                goto done;
        }
@@ -2169,7 +2686,7 @@ int connman_inet_check_ipaddress(const char *host)
 }
 
 /* Check routine modified from ics-dhcp 4.2.3-P2 */
-connman_bool_t connman_inet_check_hostname(const char *ptr, size_t len)
+bool connman_inet_check_hostname(const char *ptr, size_t len)
 {
        const char *p;
 
@@ -2177,7 +2694,7 @@ connman_bool_t connman_inet_check_hostname(const char *ptr, size_t len)
         * Not empty or complete length not over 255 characters.
         */
        if ((len == 0) || (len > 256))
-               return FALSE;
+               return false;
 
        /*
         * Consists of [[:alnum:]-]+ labels separated by [.]
@@ -2190,7 +2707,7 @@ connman_bool_t connman_inet_check_hostname(const char *ptr, size_t len)
                         * Not allowed at begin or end of a label.
                         */
                        if (((p - ptr) == 0) || (len == 0) || (p[1] == '.'))
-                               return FALSE;
+                               return false;
 
                } else if (*p == '.') {
                        /*
@@ -2200,7 +2717,7 @@ connman_bool_t connman_inet_check_hostname(const char *ptr, size_t len)
                        size_t d = p - ptr;
 
                        if ((d <= 0) || (d >= 64))
-                               return FALSE;
+                               return false;
 
                        ptr = p + 1; /* Jump to the next label */
 
@@ -2208,11 +2725,11 @@ connman_bool_t connman_inet_check_hostname(const char *ptr, size_t len)
                        /*
                         * Also numbers at the begin are fine
                         */
-                       return FALSE;
+                       return false;
                }
        }
 
-       return TRUE;
+       return true;
 }
 
 char **__connman_inet_get_running_interfaces(void)
@@ -2237,7 +2754,7 @@ char **__connman_inet_get_running_interfaces(void)
         * calls.
         */
        ifr = g_try_malloc0(ifc.ifc_len * 2);
-       if (ifr == NULL)
+       if (!ifr)
                goto error;
 
        ifc.ifc_req = ifr;
@@ -2248,7 +2765,7 @@ char **__connman_inet_get_running_interfaces(void)
        numif = ifc.ifc_len / sizeof(struct ifreq);
 
        result = g_try_malloc0((numif + 1) * sizeof(char *));
-       if (result == NULL)
+       if (!result)
                goto error;
 
        close(sk);
@@ -2283,7 +2800,14 @@ char **__connman_inet_get_running_interfaces(void)
        g_free(ifr);
 
        if (count < numif)
+       {
+               char **prev_result = result;
                result = g_try_realloc(result, (count + 1) * sizeof(char *));
+               if (!result) {
+                       g_free(prev_result);
+                       return NULL;
+               }
+       }
 
        return result;
 
@@ -2293,14 +2817,601 @@ error:
        return NULL;
 }
 
-connman_bool_t connman_inet_is_ipv6_supported()
+bool connman_inet_is_ipv6_supported()
 {
        int sk;
 
        sk = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0)
-               return FALSE;
+               return false;
 
        close(sk);
-       return TRUE;
+       return true;
+}
+
+int __connman_inet_get_interface_address(int index, int family, void *address)
+{
+       struct ifaddrs *ifaddr, *ifa;
+       int err = -ENOENT;
+       char name[IF_NAMESIZE];
+
+       if (!if_indextoname(index, name))
+               return -EINVAL;
+
+       DBG("index %d interface %s", index, name);
+
+       if (getifaddrs(&ifaddr) < 0) {
+               err = -errno;
+               DBG("Cannot get addresses err %d/%s", err, strerror(-err));
+               return err;
+       }
+
+       for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+               if (!ifa->ifa_addr)
+                       continue;
+
+               if (strncmp(ifa->ifa_name, name, IF_NAMESIZE) == 0 &&
+                                       ifa->ifa_addr->sa_family == family) {
+                       if (family == AF_INET) {
+                               struct sockaddr_in *in4 = (struct sockaddr_in *)
+                                       ifa->ifa_addr;
+                               if (in4->sin_addr.s_addr == INADDR_ANY)
+                                       continue;
+                               memcpy(address, &in4->sin_addr,
+                                                       sizeof(struct in_addr));
+                       } else if (family == AF_INET6) {
+                               struct sockaddr_in6 *in6 =
+                                       (struct sockaddr_in6 *)ifa->ifa_addr;
+                               if (memcmp(&in6->sin6_addr, &in6addr_any,
+                                               sizeof(struct in6_addr)) == 0)
+                                       continue;
+                               memcpy(address, &in6->sin6_addr,
+                                               sizeof(struct in6_addr));
+
+                       } else {
+                               err = -EINVAL;
+                               goto out;
+                       }
+
+                       err = 0;
+                       break;
+               }
+       }
+
+out:
+       freeifaddrs(ifaddr);
+       return err;
+}
+
+static int iprule_modify(int cmd, int family, uint32_t table_id,
+                       uint32_t fwmark)
+{
+       struct __connman_inet_rtnl_handle rth;
+       int ret;
+
+       memset(&rth, 0, sizeof(rth));
+
+       rth.req.n.nlmsg_type = cmd;
+       rth.req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+       rth.req.n.nlmsg_flags = NLM_F_REQUEST;
+       rth.req.u.r.rt.rtm_family = family;
+       rth.req.u.r.rt.rtm_protocol = RTPROT_BOOT;
+       rth.req.u.r.rt.rtm_scope = RT_SCOPE_UNIVERSE;
+       rth.req.u.r.rt.rtm_table = table_id;
+       rth.req.u.r.rt.rtm_type = RTN_UNSPEC;
+       rth.req.u.r.rt.rtm_flags = 0;
+
+       if (cmd == RTM_NEWRULE) {
+               rth.req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
+               rth.req.u.r.rt.rtm_type = RTN_UNICAST;
+       }
+
+       __connman_inet_rtnl_addattr32(&rth.req.n, sizeof(rth.req),
+                                                       FRA_FWMARK, fwmark);
+
+       if (table_id < 256) {
+               rth.req.u.r.rt.rtm_table = table_id;
+       } else {
+               rth.req.u.r.rt.rtm_table = RT_TABLE_UNSPEC;
+               __connman_inet_rtnl_addattr32(&rth.req.n, sizeof(rth.req),
+                                               FRA_TABLE, table_id);
+       }
+
+       if (rth.req.u.r.rt.rtm_family == AF_UNSPEC)
+               rth.req.u.r.rt.rtm_family = AF_INET;
+
+       ret = __connman_inet_rtnl_open(&rth);
+       if (ret < 0)
+               goto done;
+
+       ret = __connman_inet_rtnl_send(&rth, &rth.req.n);
+
+done:
+       __connman_inet_rtnl_close(&rth);
+
+       return ret;
+}
+
+int __connman_inet_add_fwmark_rule(uint32_t table_id, int family, uint32_t fwmark)
+{
+       /* ip rule add fwmark 9876 table 1234 */
+
+       return iprule_modify(RTM_NEWRULE, family, table_id, fwmark);
+}
+
+int __connman_inet_del_fwmark_rule(uint32_t table_id, int family, uint32_t fwmark)
+{
+       return iprule_modify(RTM_DELRULE, family, table_id, fwmark);
+}
+
+static int iproute_default_modify(int cmd, uint32_t table_id, int ifindex,
+                       const char *gateway)
+{
+       struct __connman_inet_rtnl_handle rth;
+       unsigned char buf[sizeof(struct in6_addr)];
+       int ret, len;
+       int family = connman_inet_check_ipaddress(gateway);
+
+       switch (family) {
+       case AF_INET:
+               len = 4;
+               break;
+       case AF_INET6:
+               len = 16;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = inet_pton(family, gateway, buf);
+       if (ret <= 0)
+               return -EINVAL;
+
+       memset(&rth, 0, sizeof(rth));
+
+       rth.req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+       rth.req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
+       rth.req.n.nlmsg_type = cmd;
+       rth.req.u.r.rt.rtm_family = family;
+       rth.req.u.r.rt.rtm_table = RT_TABLE_MAIN;
+       rth.req.u.r.rt.rtm_scope = RT_SCOPE_NOWHERE;
+       rth.req.u.r.rt.rtm_protocol = RTPROT_BOOT;
+       rth.req.u.r.rt.rtm_scope = RT_SCOPE_UNIVERSE;
+       rth.req.u.r.rt.rtm_type = RTN_UNICAST;
+
+       __connman_inet_rtnl_addattr_l(&rth.req.n, sizeof(rth.req), RTA_GATEWAY,
+                                                               buf, len);
+       if (table_id < 256) {
+               rth.req.u.r.rt.rtm_table = table_id;
+       } else {
+               rth.req.u.r.rt.rtm_table = RT_TABLE_UNSPEC;
+               __connman_inet_rtnl_addattr32(&rth.req.n, sizeof(rth.req),
+                                                       RTA_TABLE, table_id);
+       }
+
+       __connman_inet_rtnl_addattr32(&rth.req.n, sizeof(rth.req),
+                                                       RTA_OIF, ifindex);
+
+       ret = __connman_inet_rtnl_open(&rth);
+       if (ret < 0)
+               goto done;
+
+       ret = __connman_inet_rtnl_send(&rth, &rth.req.n);
+
+done:
+       __connman_inet_rtnl_close(&rth);
+
+       return ret;
+}
+
+int __connman_inet_add_default_to_table(uint32_t table_id, int ifindex,
+                                               const char *gateway)
+{
+       /* ip route add default via 1.2.3.4 dev wlan0 table 1234 */
+
+       return iproute_default_modify(RTM_NEWROUTE, table_id, ifindex, gateway);
+}
+
+int __connman_inet_del_default_from_table(uint32_t table_id, int ifindex,
+                                               const char *gateway)
+{
+       /* ip route del default via 1.2.3.4 dev wlan0 table 1234 */
+
+       return iproute_default_modify(RTM_DELROUTE, table_id, ifindex, gateway);
+}
+
+int __connman_inet_get_interface_ll_address(int index, int family,
+                                                               void *address)
+{
+       struct ifaddrs *ifaddr, *ifa;
+       int err = -ENOENT;
+       char name[IF_NAMESIZE];
+
+       if (!if_indextoname(index, name))
+               return -EINVAL;
+
+       DBG("index %d interface %s", index, name);
+
+       if (getifaddrs(&ifaddr) < 0) {
+               err = -errno;
+               DBG("Cannot get addresses err %d/%s", err, strerror(-err));
+               return err;
+       }
+
+       for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+               if (!ifa->ifa_addr)
+                       continue;
+
+               if (strncmp(ifa->ifa_name, name, IF_NAMESIZE) == 0 &&
+                                       ifa->ifa_addr->sa_family == family) {
+                       if (family == AF_INET) {
+                               struct sockaddr_in *in4 = (struct sockaddr_in *)
+                                       ifa->ifa_addr;
+                               if (in4->sin_addr.s_addr == INADDR_ANY)
+                                       continue;
+                               if ((in4->sin_addr.s_addr & IN_CLASSB_NET) !=
+                                               ((in_addr_t) 0xa9fe0000))
+                                       continue;
+                               memcpy(address, &in4->sin_addr,
+                                                       sizeof(struct in_addr));
+                       } else if (family == AF_INET6) {
+                               struct sockaddr_in6 *in6 =
+                                       (struct sockaddr_in6 *)ifa->ifa_addr;
+                               if (memcmp(&in6->sin6_addr, &in6addr_any,
+                                               sizeof(struct in6_addr)) == 0)
+                                       continue;
+                               if (!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr))
+                                       continue;
+
+                               memcpy(address, &in6->sin6_addr,
+                                               sizeof(struct in6_addr));
+                       } else {
+                               err = -EINVAL;
+                               goto out;
+                       }
+
+                       err = 0;
+                       break;
+               }
+       }
+
+out:
+       freeifaddrs(ifaddr);
+       return err;
+}
+
+int __connman_inet_get_address_netmask(int ifindex,
+                                       struct sockaddr_in *address,
+                                       struct sockaddr_in *netmask)
+{
+       int sk, ret = -EINVAL;
+       struct ifreq ifr;
+
+       DBG("index %d", ifindex);
+
+       sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+       if (sk < 0)
+               return -EINVAL;
+
+       memset(&ifr, 0, sizeof(ifr));
+       ifr.ifr_ifindex = ifindex;
+
+       if (ioctl(sk, SIOCGIFNAME, &ifr) < 0)
+               goto out;
+
+       if (ioctl(sk, SIOCGIFNETMASK, &ifr) < 0)
+               goto out;
+
+       memcpy(netmask, (struct sockaddr_in *)&ifr.ifr_netmask,
+                                               sizeof(struct sockaddr_in));
+
+       if (ioctl(sk, SIOCGIFADDR, &ifr) < 0)
+               goto out;
+
+       memcpy(address, (struct sockaddr_in *)&ifr.ifr_addr,
+                                               sizeof(struct sockaddr_in));
+       ret = 0;
+
+out:
+       close(sk);
+       return ret;
+}
+
+static int get_nfs_server_ip(const char *cmdline_file, const char *pnp_file,
+                               struct in_addr *addr)
+{
+       char *s, *nfsargs;
+       size_t len;
+       char addrstr[INET_ADDRSTRLEN];
+       struct in_addr taddr;
+       GError *error = NULL;
+       char *cmdline = NULL;
+       char *pnp = NULL;
+       char **args = NULL;
+       char **pnpent = NULL;
+       char **pp = NULL;
+       int err = -1;
+
+       if (!cmdline_file)
+               cmdline_file = "/proc/cmdline";
+       if (!pnp_file)
+               pnp_file = "/proc/net/pnp";
+       if (!addr)
+               addr = &taddr;
+       addr->s_addr = INADDR_NONE;
+
+       if (!g_file_get_contents(cmdline_file, &cmdline, NULL, &error)) {
+               connman_error("%s: Cannot read %s %s\n", __func__,
+                               cmdline_file, error->message);
+               goto out;
+       }
+
+       if (g_file_test(pnp_file, G_FILE_TEST_EXISTS)) {
+               if (!g_file_get_contents(pnp_file, &pnp, NULL, &error)) {
+                       connman_error("%s: Cannot read %s %s\n", __func__,
+                                                 pnp_file, error->message);
+                       goto out;
+               }
+       } else {
+               connman_error("%s: File %s doesn't exist\n", __func__, pnp_file);
+               goto out;
+       }
+
+       len = strlen(cmdline);
+       if (len <= 1) {
+               /* too short */
+               goto out;
+       }
+       /* remove newline */
+       if (cmdline[len - 1] == '\n')
+               cmdline[--len] = '\0';
+
+       /* split in arguments (seperated by space) */
+       args = g_strsplit(cmdline, " ", 0);
+       if (!args) {
+               connman_error("%s: Cannot split cmdline \"%s\"\n", __func__,
+                               cmdline);
+               goto out;
+       }
+
+       /* split in entries (by newlines) */
+       pnpent = g_strsplit(pnp, "\n", 0);
+       if (!pnpent) {
+               connman_error("%s: Cannot split pnp at file \"%s\"\n", __func__,
+                               pnp_file);
+               goto out;
+       }
+
+       /* first find root argument */
+       for (pp = args; *pp; pp++) {
+               if (!strcmp(*pp, "root=/dev/nfs"))
+                       break;
+       }
+       /* no rootnfs found */
+       if (!*pp)
+               goto out;
+
+       /* locate nfsroot argument */
+       for (pp = args; *pp; pp++) {
+               if (!strncmp(*pp, "nfsroot=", strlen("nfsroot=")))
+                       break;
+       }
+       /* no nfsroot argument found */
+       if (!*pp)
+               goto out;
+
+       /* determine if nfsroot server is provided */
+       nfsargs = strchr(*pp, '=');
+       if (!nfsargs)
+               goto out;
+       nfsargs++;
+
+       /* find whether serverip is present */
+       s = strchr(nfsargs, ':');
+       if (s) {
+               len = s - nfsargs;
+               s = nfsargs;
+       } else {
+               /* no serverip, use bootserver */
+               for (pp = pnpent; *pp; pp++) {
+                       if (!strncmp(*pp, "bootserver ", strlen("bootserver ")))
+                               break;
+               }
+               /* no bootserver found */
+               if (!*pp)
+                       goto out;
+               s = *pp + strlen("bootserver ");
+               len = strlen(s);
+       }
+
+       /* copy to addr string buffer */
+       if (len >= sizeof(addrstr)) {
+               connman_error("%s: Bad server\n", __func__);
+               goto out;
+       }
+       memcpy(addrstr, s, len);
+       addrstr[len] = '\0';
+
+       err = inet_pton(AF_INET, addrstr, addr);
+       if (err <= 0) {
+               connman_error("%s: Cannot convert to numeric addr \"%s\"\n",
+                               __func__, addrstr);
+               err = -1;
+               goto out;
+       }
+
+       /* all done */
+       err = 0;
+out:
+       g_strfreev(pnpent);
+       g_strfreev(args);
+       if (error)
+               g_error_free(error);
+       g_free(pnp);
+       g_free(cmdline);
+
+       return err;
+}
+
+/* get interface out of which peer is reachable (IPv4 only) */
+static int get_peer_iface(struct in_addr *addr, char *ifname)
+{
+       struct ifaddrs *ifaddr, *ifa;
+       struct sockaddr_in saddr, *ifsaddr;
+       socklen_t socklen;
+       int s;
+       int err = -1;
+
+       /* Obtain address(es) matching host/port */
+       err = getifaddrs(&ifaddr);
+       if (err < 0) {
+               connman_error("%s: getifaddrs() failed %d (%s)\n",
+                               __func__, errno, strerror(errno));
+               return -1;
+       }
+
+       s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+       if (s < 0) {
+               connman_error("%s: socket() failed %d (%s)\n",
+                               __func__, errno, strerror(errno));
+               return -1;
+       }
+
+       memset(&saddr, 0, sizeof(saddr));
+       saddr.sin_family = AF_INET;
+       saddr.sin_port = 0;     /* any port */
+       saddr.sin_addr = *addr;
+
+       /* no need to bind, connect will select iface */
+       err = connect(s, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
+       if (err < 0) {
+               connman_error("%s: connect() failed: %d (%s)\n",
+                               __func__, errno, strerror(errno));
+               goto out;
+       }
+
+       socklen = sizeof(saddr);
+       err = getsockname(s, (struct sockaddr *)&saddr, &socklen);
+       if (err < 0) {
+               connman_error("%s: getsockname() failed: %d (%s)\n",
+                               __func__, errno, strerror(errno));
+               goto out;
+       }
+
+       err = -1;
+       for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+               if (!ifa->ifa_addr)
+                       continue;
+
+               /* only IPv4 address */
+               if (ifa->ifa_addr->sa_family != AF_INET)
+                       continue;
+
+               ifsaddr = (struct sockaddr_in *)ifa->ifa_addr;
+
+               /* match address? */
+               if (ifsaddr->sin_addr.s_addr == saddr.sin_addr.s_addr)
+                       break;
+       }
+
+       if (ifa) {
+               err = 0;
+               if (ifname)
+                       strcpy(ifname, ifa->ifa_name);
+       }
+
+out:
+       close(s);
+
+       freeifaddrs(ifaddr);
+
+       return err;
+}
+
+bool __connman_inet_isrootnfs_device(const char *devname)
+{
+       struct in_addr addr;
+       char ifname[IFNAMSIZ];
+
+       return get_nfs_server_ip(NULL, NULL, &addr) == 0 &&
+              get_peer_iface(&addr, ifname) == 0 &&
+              strcmp(devname, ifname) == 0;
+}
+
+char **__connman_inet_get_pnp_nameservers(const char *pnp_file)
+{
+       char **pp;
+       char *s;
+       int pass, count;
+       GError *error = NULL;
+       char *pnp = NULL;
+       char **pnpent = NULL;
+       char **nameservers = NULL;
+
+       if (!pnp_file)
+               pnp_file = "/proc/net/pnp";
+
+       if (!g_file_get_contents(pnp_file, &pnp, NULL, &error)) {
+               connman_error("%s: Cannot read %s %s\n", __func__,
+                               pnp_file, error->message);
+               goto out;
+       }
+
+       /* split in entries (by newlines) */
+       pnpent = g_strsplit(pnp, "\n", 0);
+       if (!pnpent) {
+               connman_error("%s: Cannot split pnp \"%s\"\n", __func__,
+                               pnp_file);
+               goto out;
+       }
+
+       /*
+        * Perform two passes to retreive a char ** array of
+        * nameservers that are not 0.0.0.0
+        *
+        * The first pass counts them, the second fills in the
+        * array.
+        */
+       count = 0;
+       nameservers = NULL;
+       for (pass = 1; pass <= 2; pass++) {
+
+               /* at the start of the second pass allocate */
+               if (pass == 2)
+                       nameservers = g_new(char *, count + 1);
+
+               count = 0;
+               for (pp = pnpent; *pp; pp++) {
+                       /* match 'nameserver ' at the start of each line */
+                       if (strncmp(*pp, "nameserver ", strlen("nameserver ")))
+                               continue;
+
+                       /* compare it against 0.0.0.0 */
+                       s = *pp + strlen("nameserver ");
+                       if (!strcmp(s, "0.0.0.0"))
+                               continue;
+
+                       /* on second pass fill in array */
+                       if (pass == 2)
+                               nameservers[count] = g_strdup(s);
+                       count++;
+               }
+
+               /* no nameservers? */
+               if (count == 0)
+                       goto out;
+
+               /* and terminate char ** array with NULL */
+               if (pass == 2)
+                       nameservers[count] = NULL;
+
+       }
+
+out:
+       g_strfreev(pnpent);
+       g_free(pnp);
+       if (error)
+               g_error_free(error);
+
+       return nameservers;
 }