ethernet: Add tethering support
authorJukka Rissanen <jukka.rissanen@linux.intel.com>
Thu, 25 Apr 2013 11:47:51 +0000 (14:47 +0300)
committerPatrik Flykt <patrik.flykt@linux.intel.com>
Fri, 26 Apr 2013 09:33:58 +0000 (12:33 +0300)
include/technology.h
plugins/ethernet.c
src/technology.c

index 71314f2..9fe994c 100644 (file)
@@ -44,6 +44,7 @@ void connman_technology_regdom_notify(struct connman_technology *technology,
 
 connman_bool_t connman_technology_get_wifi_tethering(const char **ssid,
                                                        const char **psk);
+connman_bool_t connman_technology_is_tethering_allowed(enum connman_service_type type);
 
 struct connman_technology_driver {
        const char *name;
index 6a20eb2..bafc75d 100644 (file)
@@ -39,6 +39,9 @@
 #include <connman/inet.h>
 #include <connman/rtnl.h>
 #include <connman/log.h>
+#include <connman/setting.h>
+
+static connman_bool_t eth_tethering = FALSE;
 
 struct ethernet_data {
        int index;
@@ -107,7 +110,13 @@ static void add_network(struct connman_device *device,
                return;
        }
 
-       connman_network_set_group(network, "cable");
+       if (eth_tethering == FALSE)
+               /*
+                * Prevent service from starting the reconnect
+                * procedure as we do not want the DHCP client
+                * to run when tethering.
+                */
+               connman_network_set_group(network, "cable");
 
        ethernet->network = network;
 }
@@ -319,11 +328,102 @@ static void eth_remove(struct connman_technology *technology)
        DBG("");
 }
 
+static GList *eth_interface_list = NULL;
+
+static void eth_add_interface(struct connman_technology *technology,
+                       int index, const char *name, const char *ident)
+{
+       DBG("index %d name %s ident %s", index, name, ident);
+
+       if (g_list_find(eth_interface_list,
+                       GINT_TO_POINTER((int) index)) != NULL)
+               return;
+
+       eth_interface_list = g_list_prepend(eth_interface_list,
+                                       (GINT_TO_POINTER((int) index)));
+}
+
+static void eth_remove_interface(struct connman_technology *technology,
+                                                               int index)
+{
+       DBG("index %d", index);
+
+       eth_interface_list = g_list_remove(eth_interface_list,
+                                       GINT_TO_POINTER((int) index));
+}
+
+static void eth_enable_tethering(struct connman_technology *technology,
+                                               const char *bridge)
+{
+       GList *list;
+
+       for (list = eth_interface_list; list; list = list->next) {
+               int index = GPOINTER_TO_INT(list->data);
+               struct connman_device *device =
+                       connman_device_find_by_index(index);
+
+               if (device != NULL)
+                       connman_device_disconnect_service(device);
+
+               connman_technology_tethering_notify(technology, TRUE);
+
+               connman_inet_ifup(index);
+
+               connman_inet_add_to_bridge(index, bridge);
+
+               eth_tethering = TRUE;
+       }
+}
+
+static void eth_disable_tethering(struct connman_technology *technology,
+                                               const char *bridge)
+{
+       GList *list;
+
+       for (list = eth_interface_list; list; list = list->next) {
+               int index = GPOINTER_TO_INT(list->data);
+               struct connman_device *device =
+                       connman_device_find_by_index(index);
+
+               connman_inet_remove_from_bridge(index, bridge);
+
+               connman_inet_ifdown(index);
+
+               connman_technology_tethering_notify(technology, FALSE);
+
+               if (device != NULL)
+                       connman_device_reconnect_service(device);
+
+               eth_tethering = FALSE;
+       }
+}
+
+static int eth_set_tethering(struct connman_technology *technology,
+                               const char *identifier, const char *passphrase,
+                               const char *bridge, connman_bool_t enabled)
+{
+       if (connman_technology_is_tethering_allowed(
+                               CONNMAN_SERVICE_TYPE_ETHERNET) == FALSE)
+               return 0;
+
+       DBG("bridge %s enabled %d", bridge, enabled);
+
+       if (enabled)
+               eth_enable_tethering(technology, bridge);
+       else
+               eth_disable_tethering(technology, bridge);
+
+       return 0;
+}
+
 static struct connman_technology_driver eth_driver = {
        .name                   = "ethernet",
        .type                   = CONNMAN_SERVICE_TYPE_ETHERNET,
        .probe                  = eth_probe,
        .remove                 = eth_remove,
+       .add_interface          = eth_add_interface,
+       .remove_interface       = eth_remove_interface,
+       .set_tethering          = eth_set_tethering,
 };
 
 static int ethernet_init(void)
index f15fbd9..6e21b4b 100644 (file)
@@ -99,6 +99,30 @@ static void rfkill_check(gpointer key, gpointer value, gpointer user_data)
                                rfkill->softblock, rfkill->hardblock);
 }
 
+connman_bool_t
+connman_technology_is_tethering_allowed(enum connman_service_type type)
+{
+       static char *allowed_default[] = { "wifi", "bluetooth", "gadget",
+                                          NULL };
+       const char *type_str = __connman_service_type2string(type);
+       char **allowed;
+       int i;
+
+       if (type_str == NULL)
+               return FALSE;
+
+       allowed = connman_setting_get_string_list("AllowedTetheringTechnologies");
+       if (allowed == NULL)
+               allowed = allowed_default;
+
+       for (i = 0; allowed[i] != NULL; i++) {
+               if (g_strcmp0(allowed[i], type_str) == 0)
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
 /**
  * connman_technology_driver_register:
  * @driver: Technology driver definition
@@ -787,6 +811,13 @@ static DBusMessage *set_property(DBusConnection *conn,
                if (type != DBUS_TYPE_BOOLEAN)
                        return __connman_error_invalid_arguments(msg);
 
+               if (connman_technology_is_tethering_allowed(technology->type)
+                                                               == FALSE) {
+                       DBG("%s tethering not allowed by config file",
+                               __connman_service_type2string(technology->type));
+                       return __connman_error_not_supported(msg);
+               }
+
                dbus_message_iter_get_basic(&value, &tethering);
 
                if (technology->tethering == tethering) {