Factorize host route setting routine
[framework/connectivity/connman.git] / src / inet.c
index 3fc162c..cfb7f92 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  Connection Manager
  *
- *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
@@ -89,6 +89,36 @@ char *connman_inet_ifname(int index)
        return strdup(ifr.ifr_name);
 }
 
+short int connman_inet_ifflags(int index)
+{
+       struct ifreq ifr;
+       int sk, err;
+
+       sk = socket(PF_INET, SOCK_DGRAM, 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;
@@ -288,6 +318,36 @@ static char *index2ident(int index, const char *prefix)
        return str;
 }
 
+connman_bool_t connman_inet_is_cfg80211(int index)
+{
+       connman_bool_t result = FALSE;
+       char phy80211_path[PATH_MAX];
+       struct stat st;
+       struct ifreq ifr;
+       int sk;
+
+       sk = socket(PF_INET, SOCK_DGRAM, 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;
+
+done:
+       close(sk);
+
+       return result;
+}
+
 enum connman_device_type __connman_inet_get_device_type(int index)
 {
        enum connman_device_type devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
@@ -309,11 +369,17 @@ enum connman_device_type __connman_inet_get_device_type(int index)
        devname = ifr.ifr_name;
 
        if (type == ARPHRD_ETHER) {
-               char bridge_path[PATH_MAX], wimax_path[PATH_MAX];
+               char phy80211_path[PATH_MAX];
+               char bonding_path[PATH_MAX];
+               char bridge_path[PATH_MAX];
+               char wimax_path[PATH_MAX];
                struct stat st;
                struct iwreq iwr;
-               char *devnode;
 
+               snprintf(phy80211_path, PATH_MAX,
+                                       "/sys/class/net/%s/phy80211", devname);
+               snprintf(bonding_path, PATH_MAX,
+                                       "/sys/class/net/%s/bonding", devname);
                snprintf(bridge_path, PATH_MAX,
                                        "/sys/class/net/%s/bridge", devname);
                snprintf(wimax_path, PATH_MAX,
@@ -322,13 +388,6 @@ enum connman_device_type __connman_inet_get_device_type(int index)
                memset(&iwr, 0, sizeof(iwr));
                strncpy(iwr.ifr_ifrn.ifrn_name, devname, IFNAMSIZ);
 
-               devnode = __connman_udev_get_mbm_devnode(devname);
-               if (devnode != NULL) {
-                       devtype = CONNMAN_DEVICE_TYPE_MBM;
-                       g_free(devnode);
-                       goto done;
-               }
-
                if (g_str_has_prefix(devname, "vmnet") == TRUE)
                        devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
                else if (g_str_has_prefix(ifr.ifr_name, "vboxnet") == TRUE)
@@ -341,13 +400,14 @@ enum connman_device_type __connman_inet_get_device_type(int index)
                        devtype = CONNMAN_DEVICE_TYPE_WIMAX;
                else if (stat(bridge_path, &st) == 0 && (st.st_mode & S_IFDIR))
                        devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
+               else if (stat(bonding_path, &st) == 0 && (st.st_mode & S_IFDIR))
+                       devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
+               else if (stat(phy80211_path, &st) == 0 && (st.st_mode & S_IFDIR))
+                       devtype = CONNMAN_DEVICE_TYPE_WIFI;
                else if (ioctl(sk, SIOCGIWNAME, &iwr) == 0)
                        devtype = CONNMAN_DEVICE_TYPE_WIFI;
                else
                        devtype = CONNMAN_DEVICE_TYPE_ETHERNET;
-       } else if (type == ARPHRD_NONE) {
-               if (g_str_has_prefix(devname, "hso") == TRUE)
-                       devtype = CONNMAN_DEVICE_TYPE_HSO;
        }
 
 done:
@@ -371,13 +431,18 @@ struct connman_device *connman_inet_create_device(int index)
        if (devname == NULL)
                return NULL;
 
+       if (__connman_element_device_isfiltered(devname) == TRUE) {
+               connman_info("Ignoring interface %s (filtered)", devname);
+               return NULL;
+       }
+
        __connman_udev_get_devtype(devname);
 
        type = __connman_inet_get_device_type(index);
 
        switch (type) {
        case CONNMAN_DEVICE_TYPE_UNKNOWN:
-               connman_info("Ignoring network interface %s", devname);
+               connman_info("Ignoring interface %s (type unknown)", devname);
                g_free(devname);
                return NULL;
        case CONNMAN_DEVICE_TYPE_ETHERNET:
@@ -387,19 +452,11 @@ struct connman_device *connman_inet_create_device(int index)
                addr = index2addr(index);
                break;
        case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+       case CONNMAN_DEVICE_TYPE_CELLULAR:
        case CONNMAN_DEVICE_TYPE_GPS:
-       case CONNMAN_DEVICE_TYPE_HSO:
-       case CONNMAN_DEVICE_TYPE_NOZOMI:
-       case CONNMAN_DEVICE_TYPE_HUAWEI:
-       case CONNMAN_DEVICE_TYPE_NOVATEL:
        case CONNMAN_DEVICE_TYPE_VENDOR:
                name = strdup(devname);
                break;
-       case CONNMAN_DEVICE_TYPE_MBM:
-               name = strdup(devname);
-               addr = index2addr(index);
-               node = __connman_udev_get_mbm_devnode(devname);
-               break;
        }
 
        device = connman_device_create(name, type);
@@ -409,14 +466,11 @@ struct connman_device *connman_inet_create_device(int index)
        switch (type) {
        case CONNMAN_DEVICE_TYPE_UNKNOWN:
        case CONNMAN_DEVICE_TYPE_VENDOR:
-       case CONNMAN_DEVICE_TYPE_NOZOMI:
-       case CONNMAN_DEVICE_TYPE_HUAWEI:
-       case CONNMAN_DEVICE_TYPE_NOVATEL:
        case CONNMAN_DEVICE_TYPE_GPS:
                mode = CONNMAN_DEVICE_MODE_UNKNOWN;
                break;
        case CONNMAN_DEVICE_TYPE_ETHERNET:
-               mode = CONNMAN_DEVICE_MODE_TRANSPORT_IP;
+               mode = CONNMAN_DEVICE_MODE_NETWORK_SINGLE;
                ident = index2ident(index, NULL);
                break;
        case CONNMAN_DEVICE_TYPE_WIFI:
@@ -427,8 +481,7 @@ struct connman_device *connman_inet_create_device(int index)
        case CONNMAN_DEVICE_TYPE_BLUETOOTH:
                mode = CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE;
                break;
-       case CONNMAN_DEVICE_TYPE_MBM:
-       case CONNMAN_DEVICE_TYPE_HSO:
+       case CONNMAN_DEVICE_TYPE_CELLULAR:
                mode = CONNMAN_DEVICE_MODE_NETWORK_SINGLE;
                ident = index2ident(index, NULL);
                break;
@@ -441,7 +494,7 @@ struct connman_device *connman_inet_create_device(int index)
 
        if (ident != NULL) {
                connman_device_set_ident(device, ident);
-               g_free(ident);
+               free(ident);
        }
 
        connman_device_set_string(device, "Address", addr);
@@ -449,14 +502,13 @@ struct connman_device *connman_inet_create_device(int index)
 done:
        g_free(devname);
        g_free(node);
-       g_free(name);
-       g_free(addr);
+       free(name);
+       free(addr);
 
        return device;
 }
 
-int connman_inet_set_address(int index, struct in_addr address,
-                       struct in_addr netmask, struct in_addr broadcast)
+int connman_inet_set_address(int index, struct connman_ipaddress *ipaddress)
 {
        struct ifreq ifr;
        struct sockaddr_in addr;
@@ -476,9 +528,14 @@ int connman_inet_set_address(int index, struct in_addr address,
 
        DBG("ifname %s", ifr.ifr_name);
 
+       if (ipaddress->local == NULL) {
+               close(sk);
+               return -1;
+       }
+
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
-       addr.sin_addr = address;
+       addr.sin_addr.s_addr = inet_addr(ipaddress->local);
        memcpy(&ifr.ifr_addr, &addr, sizeof(ifr.ifr_addr));
 
        err = ioctl(sk, SIOCSIFADDR, &ifr);
@@ -488,7 +545,7 @@ int connman_inet_set_address(int index, struct in_addr address,
 
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
-       addr.sin_addr = netmask;
+       addr.sin_addr.s_addr = htonl(~(0xfffffffflu >> ipaddress->prefixlen));
        memcpy(&ifr.ifr_netmask, &addr, sizeof(ifr.ifr_netmask));
 
        err = ioctl(sk, SIOCSIFNETMASK, &ifr);
@@ -498,7 +555,13 @@ int connman_inet_set_address(int index, struct in_addr address,
 
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
-       addr.sin_addr = broadcast;
+
+       if (ipaddress->broadcast != NULL)
+               addr.sin_addr.s_addr = inet_addr(ipaddress->broadcast);
+       else
+               addr.sin_addr.s_addr = inet_addr(ipaddress->local) |
+                               htonl(0xfffffffflu >> ipaddress->prefixlen);
+
        memcpy(&ifr.ifr_broadaddr, &addr, sizeof(ifr.ifr_broadaddr));
 
        err = ioctl(sk, SIOCSIFBRDADDR, &ifr);
@@ -549,7 +612,7 @@ int connman_inet_clear_address(int index)
        return 0;
 }
 
-int connman_inet_set_gateway(int index, struct in_addr gateway)
+int connman_inet_add_host_route(int index, const char *host, const char *gateway)
 {
        struct ifreq ifr;
        struct rtentry rt;
@@ -572,15 +635,20 @@ int connman_inet_set_gateway(int index, struct in_addr gateway)
 
        memset(&rt, 0, sizeof(rt));
        rt.rt_flags = RTF_UP | RTF_HOST;
+       if (gateway != NULL)
+               rt.rt_flags |= RTF_GATEWAY;
 
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
-       addr.sin_addr = gateway;
+       addr.sin_addr.s_addr = inet_addr(host);
        memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
 
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
-       addr.sin_addr.s_addr = INADDR_ANY;
+       if (gateway != NULL)
+               addr.sin_addr.s_addr = inet_addr(gateway);
+       else
+               addr.sin_addr.s_addr = INADDR_ANY;
        memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
 
        memset(&addr, 0, sizeof(addr));
@@ -592,9 +660,76 @@ int connman_inet_set_gateway(int index, struct in_addr gateway)
 
        err = ioctl(sk, SIOCADDRT, &rt);
        if (err < 0)
-               connman_error("Setting host gateway route failed (%s)",
+               connman_error("Adding host route failed (%s)",
+                                                       strerror(errno));
+
+       close(sk);
+
+       return err;
+}
+
+int connman_inet_del_host_route(int index, const char *host)
+{
+       struct ifreq ifr;
+       struct rtentry rt;
+       struct sockaddr_in addr;
+       int sk, err;
+
+       sk = socket(PF_INET, SOCK_DGRAM, 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 | RTF_HOST;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sin_family = AF_INET;
+       addr.sin_addr.s_addr = inet_addr(host);
+       memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
+
+       rt.rt_dev = ifr.ifr_name;
+
+       err = ioctl(sk, SIOCDELRT, &rt);
+       if (err < 0)
+               connman_error("Deleting host route failed (%s)",
                                                        strerror(errno));
 
+       close(sk);
+
+       return err;
+}
+
+int connman_inet_set_gateway_address(int index, const char *gateway)
+{
+       struct ifreq ifr;
+       struct rtentry rt;
+       struct sockaddr_in addr;
+       int sk, err;
+
+       sk = socket(PF_INET, SOCK_DGRAM, 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 | RTF_GATEWAY;
 
@@ -605,7 +740,7 @@ int connman_inet_set_gateway(int index, struct in_addr gateway)
 
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
-       addr.sin_addr = gateway;
+       addr.sin_addr.s_addr = inet_addr(gateway);
        memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
 
        memset(&addr, 0, sizeof(addr));
@@ -615,10 +750,151 @@ int connman_inet_set_gateway(int index, struct in_addr gateway)
 
        err = ioctl(sk, SIOCADDRT, &rt);
        if (err < 0)
-               connman_error("Setting default route failed (%s)",
+               connman_error("Setting default gateway route failed (%s)",
+                                                       strerror(errno));
+
+       close(sk);
+
+       return err;
+}
+
+int connman_inet_set_gateway_interface(int index)
+{
+       struct ifreq ifr;
+       struct rtentry rt;
+       struct sockaddr_in addr;
+       int sk, err;
+
+       DBG("");
+
+       sk = socket(PF_INET, SOCK_DGRAM, 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.sin_family = AF_INET;
+       addr.sin_addr.s_addr = INADDR_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);
+
+       return err;
+}
+
+int connman_inet_clear_gateway_address(int index, const char *gateway)
+{
+       struct ifreq ifr;
+       struct rtentry rt;
+       struct sockaddr_in addr;
+       int sk, err;
+
+       DBG("");
+
+       sk = socket(PF_INET, SOCK_DGRAM, 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 | RTF_GATEWAY;
+
+       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_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));
+
+       err = ioctl(sk, SIOCDELRT, &rt);
+       if (err < 0)
+               connman_error("Removing default gateway route failed (%s)",
                                                        strerror(errno));
 
        close(sk);
 
        return err;
 }
+
+int connman_inet_clear_gateway_interface(int index)
+{
+       struct ifreq ifr;
+       struct rtentry rt;
+       struct sockaddr_in addr;
+       int sk, err;
+
+       DBG("");
+
+       sk = socket(PF_INET, SOCK_DGRAM, 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.sin_family = AF_INET;
+       addr.sin_addr.s_addr = INADDR_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, SIOCDELRT, &rt);
+       if (err < 0)
+               connman_error("Removing default interface route failed (%s)",
+                                                       strerror(errno));
+       close(sk);
+
+       return err;
+}