Return an error when trying to connect hidden networks
[connman] / plugins / dhclient.c
index 8847a1d..0bf9ad1 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  Connection Manager
  *
- *  Copyright (C) 2007  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2007-2009  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
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <errno.h>
 #include <unistd.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
 #include <sys/wait.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-
-#include <glib.h>
-#include <gdbus.h>
+#include <glib/gstdio.h>
 
+#define CONNMAN_API_SUBJECT_TO_CHANGE
 #include <connman/plugin.h>
-#include <connman/dhcp.h>
+#include <connman/driver.h>
+#include <connman/dbus.h>
+#include <connman/log.h>
+
+#include "inet.h"
 
 #define DHCLIENT_INTF "org.isc.dhclient"
 #define DHCLIENT_PATH "/org/isc/dhclient"
@@ -49,17 +43,17 @@ static const char *busname;
 struct dhclient_task {
        GPid pid;
        int ifindex;
-       char *ifname;
-       struct connman_iface *iface;
+       gchar *ifname;
+       struct connman_element *element;
 };
 
-static GSList *tasks = NULL;
+static GSList *task_list = NULL;
 
 static struct dhclient_task *find_task_by_pid(GPid pid)
 {
        GSList *list;
 
-       for (list = tasks; list; list = list->next) {
+       for (list = task_list; list; list = list->next) {
                struct dhclient_task *task = list->data;
 
                if (task->pid == pid)
@@ -73,7 +67,7 @@ static struct dhclient_task *find_task_by_index(int index)
 {
        GSList *list;
 
-       for (list = tasks; list; list = list->next) {
+       for (list = task_list; list; list = list->next) {
                struct dhclient_task *task = list->data;
 
                if (task->ifindex == index)
@@ -85,22 +79,27 @@ static struct dhclient_task *find_task_by_index(int index)
 
 static void kill_task(struct dhclient_task *task)
 {
-       char pathname[PATH_MAX];
+       DBG("task %p name %s pid %d", task, task->ifname, task->pid);
 
        if (task->pid > 0)
                kill(task->pid, SIGTERM);
+}
 
-       snprintf(pathname, sizeof(pathname) - 1,
-                       "%s/dhclient.%s.pid", STATEDIR, task->ifname);
-       unlink(pathname);
+static void unlink_task(struct dhclient_task *task)
+{
+       gchar *pathname;
 
-       snprintf(pathname, sizeof(pathname) - 1,
-                       "%s/dhclient.%s.leases", STATEDIR, task->ifname);
-       unlink(pathname);
+       DBG("task %p name %s pid %d", task, task->ifname, task->pid);
 
-       free(task->ifname);
+       pathname = g_strdup_printf("%s/dhclient.%s.pid",
+                                               STATEDIR, task->ifname);
+       g_unlink(pathname);
+       g_free(pathname);
 
-       g_free(task);
+       pathname = g_strdup_printf("%s/dhclient.%s.leases",
+                                               STATEDIR, task->ifname);
+       g_unlink(pathname);
+       g_free(pathname);
 }
 
 static void task_died(GPid pid, gint status, gpointer data)
@@ -108,63 +107,53 @@ static void task_died(GPid pid, gint status, gpointer data)
        struct dhclient_task *task = data;
 
        if (WIFEXITED(status))
-               printf("[DHCP] exit status %d for %s\n",
-                                       WEXITSTATUS(status), task->ifname);
+               DBG("exit status %d for %s", WEXITSTATUS(status), task->ifname);
        else
-               printf("[DHCP] signal %d killed %s\n",
-                                       WTERMSIG(status), task->ifname);
+               DBG("signal %d killed %s", WTERMSIG(status), task->ifname);
 
        g_spawn_close_pid(pid);
        task->pid = 0;
 
-       tasks = g_slist_remove(tasks, task);
+       task_list = g_slist_remove(task_list, task);
 
-       kill_task(task);
+       unlink_task(task);
+
+       g_free(task->ifname);
+       g_free(task);
 }
 
 static void task_setup(gpointer data)
 {
        struct dhclient_task *task = data;
 
-       printf("[DHCP] setup %s\n", task->ifname);
+       DBG("task %p name %s", task, task->ifname);
 }
 
-static int dhclient_request(struct connman_iface *iface)
+static int dhclient_probe(struct connman_element *element)
 {
-       struct ifreq ifr;
        struct dhclient_task *task;
        char *argv[16], *envp[1], address[128], pidfile[PATH_MAX];
        char leases[PATH_MAX], config[PATH_MAX], script[PATH_MAX];
-       int sk, err;
-
-       sk = socket(PF_INET, SOCK_DGRAM, 0);
-       if (sk < 0)
-               return -EIO;
-
-       memset(&ifr, 0, sizeof(ifr));
-       ifr.ifr_ifindex = iface->index;
 
-       err = ioctl(sk, SIOCGIFNAME, &ifr);
+       DBG("element %p name %s", element, element->name);
 
-       close(sk);
-
-       if (err < 0)
-               return -EIO;
+       if (access(DHCLIENT, X_OK) < 0)
+               return -errno;
 
        task = g_try_new0(struct dhclient_task, 1);
        if (task == NULL)
                return -ENOMEM;
 
-       task->ifindex = iface->index;
-       task->ifname = strdup(ifr.ifr_name);
-       task->iface = iface;
+       task->ifindex = element->index;
+       task->ifname = inet_index2name(element->index);
+       task->element = element;
 
        if (task->ifname == NULL) {
                g_free(task);
                return -ENOMEM;
        }
 
-       printf("[DHCP] request %s\n", task->ifname);
+       DBG("request %s", task->ifname);
 
        snprintf(address, sizeof(address) - 1, "BUSNAME=%s", busname);
        snprintf(pidfile, sizeof(pidfile) - 1,
@@ -195,40 +184,52 @@ static int dhclient_request(struct connman_iface *iface)
 
        if (g_spawn_async(NULL, argv, envp, G_SPAWN_DO_NOT_REAP_CHILD,
                                task_setup, task, &task->pid, NULL) == FALSE) {
-               printf("Failed to spawn dhclient\n");
+               connman_error("Failed to spawn dhclient");
                return -1;
        }
 
-       tasks = g_slist_append(tasks, task);
+       task_list = g_slist_append(task_list, task);
 
        g_child_watch_add(task->pid, task_died, task);
 
-       printf("[DHCP] executed %s with pid %d\n", DHCLIENT, task->pid);
+       DBG("executed %s with pid %d", DHCLIENT, task->pid);
 
        return 0;
 }
 
-static int dhclient_release(struct connman_iface *iface)
+static void dhclient_remove(struct connman_element *element)
 {
        struct dhclient_task *task;
 
-       task = find_task_by_index(iface->index);
-       if (task == NULL)
-               return -ENODEV;
+       DBG("element %p name %s", element, element->name);
 
-       printf("[DHCP] release %s\n", task->ifname);
+       task = find_task_by_index(element->index);
+       if (task != NULL)
+               task_list = g_slist_remove(task_list, task);
+
+       if (task == NULL)
+               return;
 
-       tasks = g_slist_remove(tasks, task);
+       DBG("release %s", task->ifname);
 
        kill_task(task);
+}
 
-       return 0;
+static void dhclient_change(struct connman_element *element)
+{
+       DBG("element %p name %s", element, element->name);
+
+       if (element->state == CONNMAN_ELEMENT_STATE_ERROR)
+               connman_element_set_error(element->parent,
+                                       CONNMAN_ELEMENT_ERROR_DHCP_FAILED);
 }
 
-static struct connman_dhcp_driver dhclient_driver = {
+static struct connman_driver dhclient_driver = {
        .name           = "dhclient",
-       .request        = dhclient_request,
-       .release        = dhclient_release,
+       .type           = CONNMAN_ELEMENT_TYPE_DHCP,
+       .probe          = dhclient_probe,
+       .remove         = dhclient_remove,
+       .change         = dhclient_change,
 };
 
 static DBusHandlerResult dhclient_filter(DBusConnection *conn,
@@ -237,14 +238,11 @@ static DBusHandlerResult dhclient_filter(DBusConnection *conn,
        DBusMessageIter iter, dict;
        dbus_uint32_t pid;
        struct dhclient_task *task;
-       struct connman_ipv4 ipv4;
        const char *text, *key, *value;
 
        if (dbus_message_is_method_call(msg, DHCLIENT_INTF, "notify") == FALSE)
                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
-       memset(&ipv4, 0, sizeof(ipv4));
-
        dbus_message_iter_init(msg, &iter);
 
        dbus_message_iter_get_basic(&iter, &pid);
@@ -253,9 +251,10 @@ static DBusHandlerResult dhclient_filter(DBusConnection *conn,
        dbus_message_iter_get_basic(&iter, &text);
        dbus_message_iter_next(&iter);
 
-       printf("[DHCP] change %d to %s\n", pid, text);
+       DBG("change %d to %s", pid, text);
 
        task = find_task_by_pid(pid);
+
        if (task == NULL)
                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
@@ -269,89 +268,113 @@ static DBusHandlerResult dhclient_filter(DBusConnection *conn,
                dbus_message_iter_next(&entry);
                dbus_message_iter_get_basic(&entry, &value);
 
-               printf("[DHCP] %s = %s\n", key, value);
+               DBG("%s = %s", key, value);
 
-               if (strcmp(key, "new_ip_address") == 0)
-                       inet_aton(value, &ipv4.address);
+               if (g_ascii_strcasecmp(key, "new_ip_address") == 0) {
+                       g_free(task->element->ipv4.address);
+                       task->element->ipv4.address = g_strdup(value);
+               }
 
-               if (strcmp(key, "new_subnet_mask") == 0)
-                       inet_aton(value, &ipv4.netmask);
+               if (g_ascii_strcasecmp(key, "new_subnet_mask") == 0) {
+                       g_free(task->element->ipv4.netmask);
+                       task->element->ipv4.netmask = g_strdup(value);
+               }
 
-               if (strcmp(key, "new_routers") == 0)
-                       inet_aton(value, &ipv4.gateway);
+               if (g_ascii_strcasecmp(key, "new_routers") == 0) {
+                       g_free(task->element->ipv4.gateway);
+                       task->element->ipv4.gateway = g_strdup(value);
+               }
 
-               if (strcmp(key, "new_network_number") == 0)
-                       inet_aton(value, &ipv4.network);
+               if (g_ascii_strcasecmp(key, "new_network_number") == 0) {
+                       g_free(task->element->ipv4.network);
+                       task->element->ipv4.network = g_strdup(value);
+               }
 
-               if (strcmp(key, "new_broadcast_address") == 0)
-                       inet_aton(value, &ipv4.broadcast);
+               if (g_ascii_strcasecmp(key, "new_broadcast_address") == 0) {
+                       g_free(task->element->ipv4.broadcast);
+                       task->element->ipv4.broadcast = g_strdup(value);
+               }
 
-               if (strcmp(key, "new_domain_name_servers") == 0)
-                       inet_aton(value, &ipv4.nameserver);
+               if (g_ascii_strcasecmp(key, "new_domain_name_servers") == 0) {
+                       g_free(task->element->ipv4.nameserver);
+                       task->element->ipv4.nameserver = g_strdup(value);
+               }
 
                dbus_message_iter_next(&dict);
        }
 
-       if (strcmp(text, "PREINIT") == 0)
-               connman_dhcp_update(task->iface,
-                                       CONNMAN_DHCP_STATE_INIT, &ipv4);
-       else if (strcmp(text, "BOUND") == 0 || strcmp(text, "REBOOT") == 0)
-               connman_dhcp_update(task->iface,
-                                       CONNMAN_DHCP_STATE_BOUND, &ipv4);
-       else if (strcmp(text, "RENEW") == 0 || strcmp(text, "REBIND") == 0)
-               connman_dhcp_update(task->iface,
-                                       CONNMAN_DHCP_STATE_RENEW, &ipv4);
-       else
-               connman_dhcp_update(task->iface,
-                                       CONNMAN_DHCP_STATE_FAILED, NULL);
+       if (g_ascii_strcasecmp(text, "PREINIT") == 0) {
+       } else if (g_ascii_strcasecmp(text, "BOUND") == 0 ||
+                               g_ascii_strcasecmp(text, "REBOOT") == 0) {
+               struct connman_element *element;
+               element = connman_element_create(NULL);
+               element->type = CONNMAN_ELEMENT_TYPE_IPV4;
+               element->index = task->ifindex;
+               connman_element_update(task->element);
+               if (connman_element_register(element, task->element) < 0)
+                       connman_element_unref(element);
+       } else if (g_ascii_strcasecmp(text, "RENEW") == 0 ||
+                               g_ascii_strcasecmp(text, "REBIND") == 0) {
+               connman_element_update(task->element);
+       } else if (g_ascii_strcasecmp(text, "FAIL") == 0) {
+               connman_element_set_error(task->element,
+                                               CONNMAN_ELEMENT_ERROR_FAILED);
+       } else {
+       }
 
        return DBUS_HANDLER_RESULT_HANDLED;
 }
 
 static DBusConnection *connection;
 
-static int plugin_init(void)
+static const char *dhclient_rule = "path=" DHCLIENT_PATH
+                                               ",interface=" DHCLIENT_INTF;
+
+static int dhclient_init(void)
 {
-       gchar *filter;
+       int err;
 
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+       connection = connman_dbus_get_connection();
 
        busname = dbus_bus_get_unique_name(connection);
-
-       busname = "org.freedesktop.connman";
+       busname = CONNMAN_SERVICE;
 
        dbus_connection_add_filter(connection, dhclient_filter, NULL, NULL);
 
-       filter = g_strdup_printf("interface=%s,path=%s",
-                                               DHCLIENT_INTF, DHCLIENT_PATH);
-
-       dbus_bus_add_match(connection, filter, NULL);
-
-       g_free(filter);
+       dbus_bus_add_match(connection, dhclient_rule, NULL);
 
-       connman_dhcp_register(&dhclient_driver);
+       err = connman_driver_register(&dhclient_driver);
+       if (err < 0) {
+               dbus_connection_unref(connection);
+               return err;
+       }
 
        return 0;
 }
 
-static void plugin_exit(void)
+static void dhclient_exit(void)
 {
        GSList *list;
 
-       for (list = tasks; list; list = list->next) {
+       for (list = task_list; list; list = list->next) {
                struct dhclient_task *task = list->data;
 
-               printf("[DHCP] killing process %d\n", task->pid);
+               DBG("killing process %d", task->pid);
 
                kill_task(task);
+               unlink_task(task);
        }
 
-       g_slist_free(tasks);
+       g_slist_free(task_list);
+
+       connman_driver_unregister(&dhclient_driver);
+
+       dbus_bus_remove_match(connection, dhclient_rule, NULL);
 
-       connman_dhcp_unregister(&dhclient_driver);
+       dbus_connection_remove_filter(connection, dhclient_filter, NULL);
 
        dbus_connection_unref(connection);
 }
 
-CONNMAN_PLUGIN_DEFINE("dhclient", "ISC DHCP client plugin", VERSION,
-                                               plugin_init, plugin_exit)
+CONNMAN_PLUGIN_DEFINE(dhclient, "ISC DHCP client plugin", VERSION,
+               CONNMAN_PLUGIN_PRIORITY_DEFAULT, dhclient_init, dhclient_exit)