Fix an issue where the log option is applied incorrectly
[platform/upstream/connman.git] / src / inet.c
old mode 100755 (executable)
new mode 100644 (file)
index 008f3de..08b1a25
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#define _GNU_SOURCE
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
@@ -190,6 +189,112 @@ 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
+
+bool __connman_inet_is_any_addr(const char *address, int family)
+{
+       bool ret = false;
+       struct addrinfo hints;
+       struct addrinfo *result = NULL;
+       struct sockaddr_in6 *in6 = NULL;
+       struct sockaddr_in *in4 = NULL;
+
+       if (!address || !*address)
+               goto out;
+
+       memset(&hints, 0, sizeof(struct addrinfo));
+
+       hints.ai_family = family;
+
+       if (getaddrinfo(address, NULL, &hints, &result))
+               goto out;
+
+       if (result) {
+               if (result->ai_family == AF_INET6) {
+                       in6 = (struct sockaddr_in6*)result->ai_addr;
+                       ret = IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr);
+               } else if (result->ai_family == AF_INET) {
+                       in4 = (struct sockaddr_in*)result->ai_addr;
+                       ret = in4->sin_addr.s_addr == INADDR_ANY;
+               }
+
+               freeaddrinfo(result);
+       }
+
+out:
+       return ret;
+}
+
 int connman_inet_ifindex(const char *name)
 {
        struct ifreq ifr;
@@ -347,29 +452,14 @@ void connman_inet_update_device_ident(struct connman_device *device)
        case CONNMAN_DEVICE_TYPE_GADGET:
        case CONNMAN_DEVICE_TYPE_WIFI:
                addr = index2addr(index);
-               break;
-       case CONNMAN_DEVICE_TYPE_BLUETOOTH:
-       case CONNMAN_DEVICE_TYPE_CELLULAR:
-       case CONNMAN_DEVICE_TYPE_GPS:
-       case CONNMAN_DEVICE_TYPE_VENDOR:
-               break;
-       }
-
-       switch (type) {
-       case CONNMAN_DEVICE_TYPE_VENDOR:
-       case CONNMAN_DEVICE_TYPE_GPS:
-               break;
-       case CONNMAN_DEVICE_TYPE_ETHERNET:
-       case CONNMAN_DEVICE_TYPE_GADGET:
                ident = index2ident(index, NULL);
                break;
-       case CONNMAN_DEVICE_TYPE_WIFI:
+       case CONNMAN_DEVICE_TYPE_CELLULAR:
                ident = index2ident(index, NULL);
                break;
        case CONNMAN_DEVICE_TYPE_BLUETOOTH:
-               break;
-       case CONNMAN_DEVICE_TYPE_CELLULAR:
-               ident = index2ident(index, NULL);
+       case CONNMAN_DEVICE_TYPE_GPS:
+       case CONNMAN_DEVICE_TYPE_VENDOR:
                break;
        }
 
@@ -385,6 +475,40 @@ void connman_inet_update_device_ident(struct connman_device *device)
 }
 #endif
 
+bool connman_inet_is_ifup(int index)
+{
+       int sk;
+       struct ifreq ifr;
+       bool ret = false;
+
+       sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+       if (sk < 0) {
+               connman_warn("Failed to open socket");
+               return false;
+       }
+
+       memset(&ifr, 0, sizeof(ifr));
+       ifr.ifr_ifindex = index;
+
+       if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+               connman_warn("Failed to get interface name for interface %d", index);
+               goto done;
+       }
+
+       if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
+               connman_warn("Failed to get interface flags for index %d", index);
+               goto done;
+       }
+
+       if (ifr.ifr_flags & IFF_UP)
+               ret = true;
+
+done:
+       close(sk);
+
+       return ret;
+}
+
 struct in6_ifreq {
        struct in6_addr ifr6_addr;
        __u32 ifr6_prefixlen;
@@ -533,7 +657,17 @@ int connman_inet_add_network_route(int index, const char *host,
 
        memset(&rt, 0, sizeof(rt));
        rt.rt_flags = RTF_UP;
-       if (gateway)
+
+       /*
+        * Set RTF_GATEWAY only when gateway is set and the gateway IP address
+        * is not IPv4 any address (0.0.0.0). If the given gateway IP address is
+        * any address adding of route will fail when RTF_GATEWAY set. Passing
+        * gateway as NULL or INADDR_ANY should have the same effect. Setting
+        * the gateway address later to the struct is not affected by this,
+        * since given IPv4 any address (0.0.0.0) equals the value set with
+        * INADDR_ANY.
+        */
+       if (gateway && !__connman_inet_is_any_addr(gateway, AF_INET))
                rt.rt_flags |= RTF_GATEWAY;
        if (!netmask)
                rt.rt_flags |= RTF_HOST;
@@ -696,10 +830,17 @@ int connman_inet_add_ipv6_network_route(int index, const char *host,
 
        rt.rtmsg_flags = RTF_UP | RTF_HOST;
 
-       if (gateway) {
+       /*
+        * Set RTF_GATEWAY only when gateway is set, the gateway IP address is
+        * not IPv6 any address (e.g., ::) and the address is valid (conversion
+        * succeeds). If the given gateway IP address is any address then
+        * adding of route will fail when RTF_GATEWAY set. Passing gateway as
+        * NULL or IPv6 any address should have the same effect.
+        */
+
+       if (gateway && !__connman_inet_is_any_addr(gateway, AF_INET6) &&
+               inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway) > 0)
                rt.rtmsg_flags |= RTF_GATEWAY;
-               inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway);
-       }
 
        rt.rtmsg_metric = 1;
        rt.rtmsg_ifindex = index;
@@ -1051,7 +1192,7 @@ bool connman_inet_compare_subnet(int index, const char *host)
                return false;
 
        if (inet_aton(host, &_host_addr) == 0)
-               return -1;
+               return false;
        host_addr = _host_addr.s_addr;
 
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
@@ -1341,10 +1482,9 @@ static int icmpv6_recv(int fd, struct xs_cb_data *data)
        /* 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) {
-               xs_cleanup(data);
+                       == NULL)
                return -errno;
-       }
+
        DBG("Received Source Address %s from router", src_addr);
 
        /* icmpv6_recv() function can be called in two scenarios :
@@ -2377,6 +2517,7 @@ static gboolean inet_rtnl_event(GIOChannel *chan, GIOCondition cond,
                return TRUE;
 
 cleanup:
+       rtnl_data->callback(NULL, rtnl_data->user_data);
        inet_rtnl_cleanup(rtnl_data);
        return TRUE;
 }
@@ -2529,8 +2670,6 @@ out:
                data->callback(addr, index, data->user_data);
 
        g_free(data);
-
-       return;
 }
 
 /*
@@ -2622,9 +2761,10 @@ int connman_inet_check_ipaddress(const char *host)
        addr = NULL;
 
        result = getaddrinfo(host, NULL, &hints, &addr);
-       if (result == 0)
+       if (result == 0) {
                result = addr->ai_family;
-       freeaddrinfo(addr);
+               freeaddrinfo(addr);
+       }
 
        return result;
 }
@@ -2743,8 +2883,7 @@ char **__connman_inet_get_running_interfaces(void)
 
        g_free(ifr);
 
-       if (count < numif)
-       {
+       if (count < numif) {
                char **prev_result = result;
                result = g_try_realloc(result, (count + 1) * sizeof(char *));
                if (!result) {
@@ -2827,6 +2966,41 @@ out:
        return err;
 }
 
+int __connman_inet_get_interface_mac_address(int index, uint8_t *mac_address)
+{
+       struct ifreq ifr;
+       int sk, err;
+       int ret = -EINVAL;
+
+       sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+       if (sk < 0) {
+               DBG("Open socket error");
+               return ret;
+       }
+
+       memset(&ifr, 0, sizeof(ifr));
+       ifr.ifr_ifindex = index;
+
+       err = ioctl(sk, SIOCGIFNAME, &ifr);
+       if (err < 0) {
+               DBG("Get interface name error");
+               goto done;
+       }
+
+       err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+       if (err < 0) {
+               DBG("Get MAC address error");
+               goto done;
+       }
+
+       memcpy(mac_address, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+       ret = 0;
+
+done:
+       close(sk);
+       return ret;
+}
+
 static int iprule_modify(int cmd, int family, uint32_t table_id,
                        uint32_t fwmark)
 {
@@ -2889,12 +3063,15 @@ int __connman_inet_del_fwmark_rule(uint32_t table_id, int family, uint32_t fwmar
 }
 
 static int iproute_default_modify(int cmd, uint32_t table_id, int ifindex,
-                       const char *gateway)
+                       const char *gateway, unsigned char prefixlen)
 {
        struct __connman_inet_rtnl_handle rth;
        unsigned char buf[sizeof(struct in6_addr)];
        int ret, len;
        int family = connman_inet_check_ipaddress(gateway);
+       char *dst = NULL;
+
+       DBG("gateway %s/%u table %u", gateway, prefixlen, table_id);
 
        switch (family) {
        case AF_INET:
@@ -2907,7 +3084,19 @@ static int iproute_default_modify(int cmd, uint32_t table_id, int ifindex,
                return -EINVAL;
        }
 
-       ret = inet_pton(family, gateway, buf);
+       if (prefixlen) {
+               struct in_addr ipv4_subnet_addr, ipv4_mask;
+
+               memset(&ipv4_subnet_addr, 0, sizeof(ipv4_subnet_addr));
+               ipv4_mask.s_addr = htonl((0xffffffff << (32 - prefixlen)) & 0xffffffff);
+               ipv4_subnet_addr.s_addr = inet_addr(gateway);
+               ipv4_subnet_addr.s_addr &= ipv4_mask.s_addr;
+
+               dst = g_strdup(inet_ntoa(ipv4_subnet_addr));
+       }
+
+       ret = inet_pton(family, dst ? dst : gateway, buf);
+       g_free(dst);
        if (ret <= 0)
                return -EINVAL;
 
@@ -2922,9 +3111,11 @@ static int iproute_default_modify(int cmd, uint32_t table_id, int ifindex,
        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;
+       rth.req.u.r.rt.rtm_dst_len = prefixlen;
+
+       __connman_inet_rtnl_addattr_l(&rth.req.n, sizeof(rth.req),
+               prefixlen > 0 ? RTA_DST : RTA_GATEWAY, buf, len);
 
-       __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 {
@@ -2953,7 +3144,14 @@ int __connman_inet_add_default_to_table(uint32_t table_id, int ifindex,
 {
        /* ip route add default via 1.2.3.4 dev wlan0 table 1234 */
 
-       return iproute_default_modify(RTM_NEWROUTE, table_id, ifindex, gateway);
+       return iproute_default_modify(RTM_NEWROUTE, table_id, ifindex, gateway, 0);
+}
+
+int __connman_inet_add_subnet_to_table(uint32_t table_id, int ifindex,
+                                               const char *gateway, unsigned char prefixlen)
+{
+       /* ip route add 1.2.3.4/24 dev eth0 table 1234 */
+       return iproute_default_modify(RTM_NEWROUTE, table_id, ifindex, gateway, prefixlen);
 }
 
 int __connman_inet_del_default_from_table(uint32_t table_id, int ifindex,
@@ -2961,7 +3159,14 @@ int __connman_inet_del_default_from_table(uint32_t table_id, int ifindex,
 {
        /* ip route del default via 1.2.3.4 dev wlan0 table 1234 */
 
-       return iproute_default_modify(RTM_DELROUTE, table_id, ifindex, gateway);
+       return iproute_default_modify(RTM_DELROUTE, table_id, ifindex, gateway, 0);
+}
+
+int __connman_inet_del_subnet_from_table(uint32_t table_id, int ifindex,
+                                               const char *gateway, unsigned char prefixlen)
+{
+       /* ip route del 1.2.3.4/24 dev eth0 table 1234 */
+       return iproute_default_modify(RTM_DELROUTE, table_id, ifindex, gateway, prefixlen);
 }
 
 int __connman_inet_get_interface_ll_address(int index, int family,
@@ -3096,10 +3301,8 @@ static int get_nfs_server_ip(const char *cmdline_file, const char *pnp_file,
                                                  pnp_file, error->message);
                        goto out;
                }
-       } else {
-               connman_error("%s: File %s doesn't exist\n", __func__, pnp_file);
+       } else
                goto out;
-       }
 
        len = strlen(cmdline);
        if (len <= 1) {
@@ -3295,6 +3498,9 @@ char **__connman_inet_get_pnp_nameservers(const char *pnp_file)
        if (!pnp_file)
                pnp_file = "/proc/net/pnp";
 
+       if (!g_file_test(pnp_file, G_FILE_TEST_EXISTS))
+               goto out;
+
        if (!g_file_get_contents(pnp_file, &pnp, NULL, &error)) {
                connman_error("%s: Cannot read %s %s\n", __func__,
                                pnp_file, error->message);