summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2007-06-28 19:19:54 +0000
committerDan Williams <dcbw@redhat.com>2007-06-28 19:19:54 +0000
commit0e9f10f311af3b7603a2eaa00136140bb45cb9a1 (patch)
tree659010efc253c5165ec7397cc21380a943dd8407
parentf235c3b3a35bd6cd0d2eeb3f1ee35ad3268788a2 (diff)
downloadNetworkManager-0e9f10f311af3b7603a2eaa00136140bb45cb9a1.tar.gz
2007-06-28 Dan Williams <dcbw@redhat.com>
Get rid of dhcdbd, based on a patch from Robert Frank. Drive dhclient directly. Big refactor to make the DHCP manager a GObject subclass with signals on DHCP events. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/branches/nm-0-6-olpc@2621 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
-rw-r--r--ChangeLog6
-rw-r--r--callouts/Makefile.am4
-rwxr-xr-xcallouts/nm-dhcp-client.action12
-rw-r--r--callouts/nm-dhcp-client.conf14
-rw-r--r--configure.in13
-rw-r--r--src/NetworkManager.c4
-rw-r--r--src/NetworkManagerDbus.c19
-rw-r--r--src/NetworkManagerMain.h2
-rw-r--r--src/NetworkManagerPolicy.c38
-rw-r--r--src/NetworkManagerPolicy.h2
-rw-r--r--src/dhcp-manager/Makefile.am28
-rw-r--r--src/dhcp-manager/nm-dhcp-manager.c1312
-rw-r--r--src/dhcp-manager/nm-dhcp-manager.h97
-rw-r--r--src/dhcp-manager/nm-dhcp-marshal-main.c3
-rw-r--r--src/dhcp-manager/nm-dhcp-marshal.list2
-rw-r--r--src/nm-activation-request.c37
-rw-r--r--src/nm-activation-request.h6
-rw-r--r--src/nm-device-802-11-mesh-olpc.c23
-rw-r--r--src/nm-device.c158
19 files changed, 1056 insertions, 724 deletions
diff --git a/ChangeLog b/ChangeLog
index 54c583380d..610cd21978 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2007-06-28 Dan Williams <dcbw@redhat.com>
+
+ Get rid of dhcdbd, based on a patch from Robert Frank. Drive dhclient
+ directly. Big refactor to make the DHCP manager a GObject subclass with
+ signals on DHCP events.
+
2007-06-22 Dan Williams <dcbw@redhat.com>
* callouts/nm-avahi-autoipd.action
diff --git a/callouts/Makefile.am b/callouts/Makefile.am
index 2d681bb1b9..6241e2c757 100644
--- a/callouts/Makefile.am
+++ b/callouts/Makefile.am
@@ -1,8 +1,8 @@
dbusservicedir = $(DBUS_SYS_DIR)
-dbusservice_DATA = nm-avahi-autoipd.conf
+dbusservice_DATA = nm-avahi-autoipd.conf nm-dhcp-client.conf
calloutdir = $(sysconfdir)/NetworkManager/callouts
-callout_DATA = nm-avahi-autoipd.action
+callout_DATA = nm-avahi-autoipd.action nm-dhcp-client.action
EXTRA_DIST = \
$(dbusservice_DATA) \
diff --git a/callouts/nm-dhcp-client.action b/callouts/nm-dhcp-client.action
new file mode 100755
index 0000000000..73725711b0
--- /dev/null
+++ b/callouts/nm-dhcp-client.action
@@ -0,0 +1,12 @@
+#!/bin/bash
+# nm-dhcp-client.action
+# sends a dbus message to the dhcp-client in nm with environmental variables
+# from the dhcp server response
+
+#Network Manager's way of doing this
+/bin/dbus-send \
+ --system \
+ --type=signal \
+ / \
+ org.freedesktop.nm_dhcp_client.Event \
+ 'string:[dhclient]'"`echo && env | /bin/egrep -v '^(PATH|SHLVL|_|PWD|dhc_dbus)\='`";
diff --git a/callouts/nm-dhcp-client.conf b/callouts/nm-dhcp-client.conf
new file mode 100644
index 0000000000..515a1106c6
--- /dev/null
+++ b/callouts/nm-dhcp-client.conf
@@ -0,0 +1,14 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <policy user="root">
+ <allow own="org.freedesktop.nm_dhcp_client"/>
+ <allow send_interface="org.freedesktop.nm_dhcp_client"/>
+ </policy>
+ <policy context="default">
+ <deny own="org.freedesktop.nm_dhcp_client"/>
+ <deny send_interface="org.freedesktop.nm_dhcp_client"/>
+ </policy>
+</busconfig>
+
diff --git a/configure.in b/configure.in
index d86b47180f..68c359fa43 100644
--- a/configure.in
+++ b/configure.in
@@ -200,19 +200,6 @@ fi
AC_SUBST(DBUS_SYS_DIR)
AC_DEFINE_UNQUOTED(DBUS_SYSTEMD_DIR, "$DBUS_SYS_DIR", [Where system.d dir for DBUS is])
-# dhcdbd binary path
-AC_ARG_WITH(dhcdbd, AC_HELP_STRING([--with-dhcdbd=/path/to/dhcdbd], [path to dhcdbd]))
-if test "x${with_dhcdbd}" = x; then
- AC_PATH_PROG(DHCDBD_BINARY_PATH, dhcdbd, [], $PATH:/sbin:/usr/sbin)
- if ! test -x "$DHCDBD_BINARY_PATH"; then
- AC_MSG_ERROR(dhcdbd was not installed. See http://people.redhat.com/jvdias/dhcdbd)
- fi
-else
- DHCDBD_BINARY_PATH="$with_dhcdbd"
-fi
-AC_DEFINE_UNQUOTED(DHCDBD_BINARY_PATH, "$DHCDBD_BINARY_PATH", [Define to path of dhcdbd binary])
-AC_SUBST(DHCDBD_BINARY_PATH)
-
# wpa_supplicant binary path
AC_ARG_WITH(wpa_supplicant, AC_HELP_STRING([--with-wpa_supplicant=/path/to/wpa_supplicant], [path to wpa_supplicant]))
if test "x${with_wpa_supplicant}" = x; then
diff --git a/src/NetworkManager.c b/src/NetworkManager.c
index 613ba59572..1f05b1fe7f 100644
--- a/src/NetworkManager.c
+++ b/src/NetworkManager.c
@@ -734,7 +734,6 @@ static void nm_data_free (NMData *data)
nm_ap_list_unref (data->invalid_ap_list);
nm_vpn_manager_dispose (data->vpn_manager);
- nm_dhcp_manager_dispose (data->dhcp_manager);
g_object_unref (data->named_manager);
g_main_loop_unref (data->main_loop);
@@ -891,6 +890,7 @@ int main( int argc, char *argv[] )
char * owner;
char * pidfile = NULL;
char * user_pidfile = NULL;
+ NMDHCPManager * dhcp_mgr;
if (getuid () != 0)
{
@@ -981,8 +981,8 @@ int main( int argc, char *argv[] )
/* Need to happen after DBUS is initialized */
nm_data->vpn_manager = nm_vpn_manager_new (nm_data);
- nm_data->dhcp_manager = nm_dhcp_manager_new (nm_data);
nm_data->named_manager = nm_named_manager_new (nm_data->dbus_connection);
+ dhcp_mgr = nm_dhcp_manager_get (nm_data);
/* If NMI is running, grab allowed wireless network lists from it ASAP */
if (nm_dbus_is_info_daemon_running (nm_data->dbus_connection))
diff --git a/src/NetworkManagerDbus.c b/src/NetworkManagerDbus.c
index 43e419b16a..3631011c94 100644
--- a/src/NetworkManagerDbus.c
+++ b/src/NetworkManagerDbus.c
@@ -311,7 +311,6 @@ nm_dbus_signal_mesh_device_change (gpointer user_data)
char * mesh_dev_path = NULL;
char * primary_dev_path = NULL;
const char * sig;
- int i = 0;
g_return_val_if_fail (cb_data->data, FALSE);
g_return_val_if_fail (cb_data->data->dbus_connection, FALSE);
@@ -615,6 +614,7 @@ static DBusHandlerResult nm_dbus_signal_filter (DBusConnection *connection, DBus
const char * method;
gboolean handled = FALSE;
DBusError error;
+ NMDHCPManager * dhcp_manager = nm_dhcp_manager_get (NULL);
g_return_val_if_fail (data != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
g_return_val_if_fail (connection != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
@@ -673,7 +673,6 @@ static DBusHandlerResult nm_dbus_signal_filter (DBusConnection *connection, DBus
nm_hal_deinit (data);
dbus_connection_unref (data->dbus_connection);
data->dbus_connection = NULL;
- nm_dhcp_manager_dispose (data->dhcp_manager);
g_thread_create ((GThreadFunc) nm_dbus_reinit, (gpointer) data, FALSE, NULL);
handled = TRUE;
}
@@ -720,18 +719,15 @@ static DBusHandlerResult nm_dbus_signal_filter (DBusConnection *connection, DBus
handled = TRUE;
}
}
- else if (nm_dhcp_manager_process_name_owner_changed (data->dhcp_manager, service, old_owner, new_owner) == TRUE)
- handled = TRUE;
else if (nm_vpn_manager_process_name_owner_changed (data->vpn_manager, service, old_owner, new_owner) == TRUE)
handled = TRUE;
else if (nm_named_manager_process_name_owner_changed (data->named_manager, service, old_owner, new_owner) == TRUE)
handled = TRUE;
}
- }
- else if (dbus_message_is_signal (message, AUTOIPD_CALLOUT_INTERFACE, "AutoIP4Event")) {
+ } else if (dbus_message_is_signal (message, AUTOIPD_CALLOUT_INTERFACE, "AutoIP4Event")) {
handled = nm_dbus_autoip_process_signal (data, message);
- } else if (nm_dhcp_manager_process_signal (data->dhcp_manager, message) == TRUE) {
- handled = TRUE;
+ } else if (dbus_message_is_signal (message, DHCP_CALLOUT_INTERFACE, "Event")) {
+ handled = nm_dhcp_manager_process_signal (dhcp_manager, message);
} else if (nm_vpn_manager_process_signal (data->vpn_manager, message) == TRUE) {
handled = TRUE;
}
@@ -935,8 +931,6 @@ static gpointer nm_dbus_reinit (gpointer user_data)
if ((owner = get_name_owner (data->dbus_connection, "org.freedesktop.Hal")))
nm_hal_init (data);
- data->dhcp_manager = nm_dhcp_manager_new (data);
-
nm_info ("Successfully reconnected to the system bus.");
return NULL;
@@ -1005,6 +999,11 @@ DBusConnection *nm_dbus_init (NMData *data)
"interface='" AUTOIPD_CALLOUT_INTERFACE "'",
NULL);
+ dbus_bus_add_match (connection,
+ "type='signal',"
+ "interface='" DHCP_CALLOUT_INTERFACE "'",
+ NULL);
+
if ((owner = get_name_owner (connection, NMI_DBUS_SERVICE)))
{
char *match = get_nmi_match_string (owner);
diff --git a/src/NetworkManagerMain.h b/src/NetworkManagerMain.h
index be550b6ba2..e44cad7c6a 100644
--- a/src/NetworkManagerMain.h
+++ b/src/NetworkManagerMain.h
@@ -49,7 +49,6 @@ typedef struct NMDbusMethodList NMDbusMethodList;
typedef struct NMActRequest NMActRequest;
typedef struct NMVPNActRequest NMVPNActRequest;
typedef struct NMVPNManager NMVPNManager;
-typedef struct NMDHCPManager NMDHCPManager;
#define DHCP_SERVICE_NAME "com.redhat.dhcp"
#define DHCP_OBJECT_PATH "/com/redhat/dhcp"
@@ -65,7 +64,6 @@ typedef struct NMData
NMNamedManager * named_manager;
NMVPNManager * vpn_manager;
- NMDHCPManager * dhcp_manager;
DBusConnection * dbus_connection;
NMDbusMethodList * nm_methods;
diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c
index 542cb7fb79..9f67b831bb 100644
--- a/src/NetworkManagerPolicy.c
+++ b/src/NetworkManagerPolicy.c
@@ -188,6 +188,44 @@ void nm_policy_schedule_activation_failed (NMActRequest *req)
}
+static gboolean nm_policy_deactivate (gpointer user_data)
+{
+ NMDevice * dev = NM_DEVICE (user_data);
+ NMData * data = NULL;
+
+ g_return_val_if_fail (dev != NULL, FALSE);
+
+ data = nm_device_get_app_data (dev);
+ g_assert (data);
+
+ nm_device_deactivate (dev);
+ g_object_unref (dev);
+
+ nm_schedule_state_change_signal_broadcast (data);
+ nm_policy_schedule_device_change_check (data);
+ return FALSE;
+}
+
+void nm_policy_schedule_deactivate (NMDevice * dev)
+{
+ GSource * source;
+ NMData * data;
+
+ g_return_if_fail (dev != NULL);
+
+ data = nm_device_get_app_data (dev);
+ g_assert (data);
+
+ source = g_idle_source_new ();
+ g_source_set_priority (source, G_PRIORITY_HIGH_IDLE);
+ g_object_ref (dev);
+ g_source_set_callback (source, (GSourceFunc) nm_policy_deactivate, dev, NULL);
+ g_source_attach (source, data->main_context);
+ g_source_unref (source);
+ nm_info ("Activation (%s) deactivation scheduled...", nm_device_get_iface (dev));
+}
+
+
/*
* nm_policy_auto_get_best_device
*
diff --git a/src/NetworkManagerPolicy.h b/src/NetworkManagerPolicy.h
index d927e1d6a3..cbe33a4971 100644
--- a/src/NetworkManagerPolicy.h
+++ b/src/NetworkManagerPolicy.h
@@ -37,6 +37,8 @@ void nm_policy_schedule_device_ap_lists_update_from_allowed (NMData *app_data)
void nm_policy_schedule_activation_finish (NMActRequest *req);
void nm_policy_schedule_activation_failed (NMActRequest *req);
+void nm_policy_schedule_deactivate (NMDevice * dev);
+
void nm_policy_add_nbd_notifier (NMDevice *dev);
#endif
diff --git a/src/dhcp-manager/Makefile.am b/src/dhcp-manager/Makefile.am
index 500c9b32dd..c66943c7f5 100644
--- a/src/dhcp-manager/Makefile.am
+++ b/src/dhcp-manager/Makefile.am
@@ -6,8 +6,14 @@ INCLUDES = -I${top_srcdir} \
noinst_LTLIBRARIES = libdhcp-manager.la
-libdhcp_manager_la_SOURCES = nm-dhcp-manager.c \
- nm-dhcp-manager.h
+BUILT_SOURCES = \
+ nm-dhcp-marshal.h \
+ nm-dhcp-marshal.c
+
+libdhcp_manager_la_SOURCES = \
+ nm-dhcp-manager.c \
+ nm-dhcp-manager.h \
+ nm-dhcp-marshal-main.c
libdhcp_manager_la_CPPFLAGS = $(DBUS_CFLAGS) \
$(GTHREAD_CFLAGS) \
@@ -22,3 +28,21 @@ libdhcp_manager_la_CPPFLAGS = $(DBUS_CFLAGS) \
libdhcp_manager_la_LIBADD = $(DBUS_LIBS) $(GTHREAD_LIBS)
+
+EXTRA_DIST = nm-dhcp-marshal.list
+CLEANFILES = $(BUILT_SOURCES)
+
+nm-dhcp-marshal.h: nm-dhcp-marshal.list
+ $(GLIB_GENMARSHAL) --prefix=nm_dhcp_marshal $(srcdir)/nm-dhcp-marshal.list --header > \
+ xgen-gmh \
+ && (cmp -s xgen-gmh nm-dhcp-marshal.h || cp xgen-gmh nm-dhcp-marshal.h) \
+ && rm -f xgen-gmh xgen-gmh~
+
+nm-dhcp-marshal.c: nm-dhcp-marshal.list
+ $(GLIB_GENMARSHAL) --prefix=nm_dhcp_marshal $(srcdir)/nm-dhcp-marshal.list --body > \
+ xgen-gmc \
+ && cp xgen-gmc nm-dhcp-marshal.c \
+ && rm -f xgen-gmc xgen-gmc~
+
+nm-dhcp-marshal-main.c: nm-dhcp-marshal.c nm-dhcp-marshal.h
+
diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c
index 3bf49f2a0f..751d214f27 100644
--- a/src/dhcp-manager/nm-dhcp-manager.c
+++ b/src/dhcp-manager/nm-dhcp-manager.c
@@ -24,758 +24,912 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <string.h>
#include "nm-dhcp-manager.h"
-#include "nm-device.h"
-#include "NetworkManagerPolicy.h"
-#include "NetworkManagerUtils.h"
-#include "NetworkManagerSystem.h"
-#include "nm-activation-request.h"
+#include "nm-dhcp-marshal.h"
#include "nm-utils.h"
+#include "NetworkManagerUtils.h"
-#define NM_DHCP_TIMEOUT 45 /* DHCP timeout, in seconds */
+#define NM_DHCP_TIMEOUT 45 /* DHCP timeout, in seconds */
-struct NMDHCPManager
+static const char *dhclient_binary_paths[] =
{
+ "/sbin/dhclient",
+ "/usr/sbin/dhclient",
+ "/usr/local/sbin/dhclient",
+ NULL
+};
+
+typedef struct {
+ char * iface;
+ guchar state;
+ GPid dhclient_pid;
+ GSource * timeout_source;
+ GSource * cancel_source;
+ GSource * watch_source;
+ NMDHCPManager * manager;
+ GHashTable * options;
+} NMDHCPDevice;
+
+typedef struct {
+ GHashTable * devices;
NMData * data;
- gboolean running;
- size_t dhcp_sn_len;
+} NMDHCPManagerPrivate;
+
+
+#define NM_DHCP_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_MANAGER, NMDHCPManagerPrivate))
+
+G_DEFINE_TYPE (NMDHCPManager, nm_dhcp_manager, G_TYPE_OBJECT)
+
+enum {
+ STATE_CHANGED,
+ TIMEOUT,
+
+ LAST_SIGNAL
};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static NMDHCPManager *nm_dhcp_manager_new (NMData * data);
+
+static void nm_dhcp_manager_cancel_transaction_real (NMDHCPDevice *device, gboolean blocking);
+
+static char *
+get_pidfile_for_iface (const char * iface)
+{
+ return g_strdup_printf ("%s/%s-%s.%s",
+ NM_DHCP_MANAGER_PID_DIR,
+ NM_DHCP_MANAGER_PID_FILENAME,
+ iface,
+ NM_DHCP_MANAGER_PID_FILE_EXT);
+}
+
+
+NMDHCPManager *
+nm_dhcp_manager_get (NMData * data)
+{
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+ static NMDHCPManager *singleton = NULL;
+
+ g_static_mutex_lock (&mutex);
+ if (!singleton) {
+ if (!data) {
+ nm_error ("Initial creation must pass NMData");
+ g_assert_not_reached ();
+ }
+ singleton = nm_dhcp_manager_new (data);
+ }
+ g_object_ref (singleton);
+ g_static_mutex_unlock (&mutex);
+
+ return singleton;
+}
-char *get_dhcp_match_string (const char *owner)
+static void
+nm_dhcp_manager_init (NMDHCPManager *msg)
{
- g_return_val_if_fail (owner != NULL, NULL);
+}
- return g_strdup_printf ("type='signal',interface='" DHCP_SERVICE_NAME ".state',sender='%s'", owner);
+static void
+finalize (GObject *object)
+{
+ G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->finalize (object);
}
+static void
+nm_dhcp_manager_class_init (NMDHCPManagerClass *manager_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
+
+ g_type_class_add_private (manager_class, sizeof (NMDHCPManagerPrivate));
+
+ /* virtual methods */
+ object_class->finalize = finalize;
+
+ /* signals */
+ signals[STATE_CHANGED] =
+ g_signal_new ("state-changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (NMDHCPManagerClass, state_changed),
+ NULL, NULL,
+ nm_dhcp_marshal_VOID__STRING_UCHAR,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_UCHAR);
+
+ signals[TIMEOUT] =
+ g_signal_new ("timeout",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (NMDHCPManagerClass, timeout),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+}
static gboolean state_is_bound (guint8 state)
{
- if ( (state == 2) /* BOUND */
- || (state == 3) /* RENEW */
- || (state == 4) /* REBOOT */
- || (state == 5)) /* REBIND */
+ if ((state == DHC_BOUND)
+ || (state == DHC_RENEW)
+ || (state == DHC_REBOOT)
+ || (state == DHC_REBIND)
+ || (state == DHC_START))
return TRUE;
return FALSE;
}
-static gboolean state_is_down (guint8 state)
+static void
+nm_dhcp_device_timeout_cleanup (NMDHCPDevice * device)
{
- if ( (state == 0) /* NBI */
- || (state == 11) /* RELEASE */
- || (state == 13) /* ABEND */
- || (state == 14)) /* END */
- return TRUE;
-
- return FALSE;
+ if (!device->timeout_source)
+ return;
+ g_source_destroy (device->timeout_source);
+ g_source_unref (device->timeout_source);
+ device->timeout_source = NULL;
}
+static void
+nm_dhcp_device_cancel_cleanup (NMDHCPDevice * device)
+{
+ if (!device->cancel_source)
+ return;
+fprintf (stderr, "%s: cleaning up cancel source %p\n", __func__, device->cancel_source);
+ g_source_destroy (device->cancel_source);
+ g_source_unref (device->cancel_source);
+ device->cancel_source = NULL;
+}
-NMDHCPManager * nm_dhcp_manager_new (NMData *data)
+static void
+nm_dhcp_device_watch_cleanup (NMDHCPDevice * device)
{
- NMDHCPManager * manager;
- char * owner;
+ if (!device->watch_source)
+ return;
+ g_source_destroy (device->watch_source);
+ g_source_unref (device->watch_source);
+ device->watch_source = NULL;
+}
- g_return_val_if_fail (data != NULL, NULL);
- g_return_val_if_fail (data->dbus_connection != NULL, NULL);
+static void
+nm_dhcp_device_destroy (NMDHCPDevice *device)
+{
+ nm_dhcp_device_timeout_cleanup (device);
+fprintf (stderr, "%s: calling cancel_cleanup\n", __func__);
+ nm_dhcp_device_cancel_cleanup (device);
+ nm_dhcp_device_watch_cleanup (device);
+ g_hash_table_remove_all (device->options);
+ g_free (device->iface);
+ g_slice_free (NMDHCPDevice, device);
+}
- manager = g_malloc0 (sizeof (NMDHCPManager));
- manager->data = data;
- manager->running = dbus_bus_name_has_owner (manager->data->dbus_connection, DHCP_SERVICE_NAME, NULL);
- manager->dhcp_sn_len = strlen (DHCP_SERVICE_NAME);
- if (manager->running && (owner = get_name_owner (data->dbus_connection, DHCP_SERVICE_NAME)))
+static inline const char *
+state_to_string (guint32 state)
+{
+ switch (state)
{
- char *match = get_dhcp_match_string (owner);
- dbus_bus_add_match (data->dbus_connection, match, NULL);
- g_free (match);
- g_free (owner);
+ case DHC_PREINIT:
+ return "preinit";
+ case DHC_BOUND:
+ return "bound";
+ case DHC_RENEW:
+ return "renew";
+ case DHC_REBOOT:
+ return "reboot";
+ case DHC_REBIND:
+ return "rebind";
+ case DHC_STOP:
+ return "stop";
+ case DHC_MEDIUM:
+ return "medium";
+ case DHC_TIMEOUT:
+ return "timeout";
+ case DHC_FAIL:
+ return "fail";
+ case DHC_EXPIRE:
+ return "expire";
+ case DHC_RELEASE:
+ return "release";
+ case DHC_START:
+ return "successfully started";
+ case DHC_ABEND:
+ return "abnormal exit";
+ case DHC_END:
+ return "normal exit";
+ default:
+ break;
}
-
- return manager;
+ return NULL;
}
-
-void nm_dhcp_manager_dispose (NMDHCPManager *manager)
+static inline guint32
+string_to_state (const char *state)
{
- g_return_if_fail (manager != NULL);
-
- memset (manager, 0, sizeof (NMDHCPManager));
- g_free (manager);
+ if (strcmp("PREINIT", state) == 0)
+ return DHC_PREINIT;
+ else if (strcmp("BOUND", state) == 0)
+ return DHC_BOUND;
+ else if (strcmp("RENEW", state) == 0)
+ return DHC_RENEW;
+ else if (strcmp("REBOOT", state) == 0)
+ return DHC_REBOOT;
+ else if (strcmp("REBIND", state) == 0)
+ return DHC_REBIND;
+ else if (strcmp("STOP", state) == 0)
+ return DHC_STOP;
+ else if (strcmp("MEDIUM", state) == 0)
+ return DHC_MEDIUM;
+ else if (strcmp("TIMEOUT", state) == 0)
+ return DHC_TIMEOUT;
+ else if (strcmp("FAIL", state) == 0)
+ return DHC_FAIL;
+ else if (strcmp("EXPIRE", state) == 0)
+ return DHC_EXPIRE;
+ else if (strcmp("RELEASE", state) == 0)
+ return DHC_RELEASE;
+ else if (strcmp("START", state) == 0)
+ return DHC_START;
+ else if (strcmp("ABEND", state) == 0)
+ return DHC_ABEND;
+ else if (strcmp("END", state) == 0)
+ return DHC_END;
+ else
+ return 255;
}
-guint32 nm_dhcp_manager_get_state_for_device (NMDHCPManager *manager, NMDevice *dev)
+/*
+ * nm_dhcp_dbus_set_state
+ *
+ * Set the dhcp state for the interface (and store the data that dhclient gave us)
+ *
+ */
+static gboolean
+nm_dhcp_dbus_set_state (NMDHCPManager *manager,
+ DBusMessage *message)
{
- DBusMessage * message;
- DBusMessage * reply;
- char * path;
- guint32 state = 0;
+ NMDHCPManagerPrivate * priv;
+ NMDHCPDevice * device;
+ const char * data = NULL;
DBusError error;
+ gboolean success = FALSE;
+ char * iface;
+ gchar ** keys;
+ GKeyFile * keyfile = NULL;
+ GError * gerror = NULL;
+ gsize length;
+ int i;
- g_return_val_if_fail (manager != NULL, 0);
- g_return_val_if_fail (dev != NULL, 0);
+ g_return_val_if_fail (manager != NULL, FALSE);
+ g_return_val_if_fail (message != NULL, FALSE);
+
+ priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
- if (!manager->running)
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &data,
+ DBUS_TYPE_INVALID))
{
- nm_warning ("dhcdbd not running!");
- return 0;
+ nm_warning ("Could not process the request because its arguments were "
+ " invalid. dbus said: '%s'",
+ error.message);
+ dbus_error_free (&error);
+ goto out;
}
- path = g_strdup_printf (DHCP_OBJECT_PATH"/%s", nm_device_get_iface (dev));
- message = dbus_message_new_method_call (DHCP_SERVICE_NAME, path, DHCP_SERVICE_NAME".dbus.get", "reason");
- g_free (path);
- if (message == NULL)
- {
- nm_warning ("nm_dhcp_manager_get_state_for_device(): Couldn't allocate the dbus message");
- return 0;
+ keyfile = g_key_file_new ();
+ if (!g_key_file_load_from_data (keyfile,
+ (gchar *) data,
+ strlen (data),
+ 0,
+ &gerror)) {
+ nm_warning ("Unable to parse data from dhclient: '%s'", gerror->message);
+ g_error_free (gerror);
+ goto out;
}
- dbus_error_init (&error);
- reply = dbus_connection_send_with_reply_and_block (manager->data->dbus_connection, message, -1, &error);
- dbus_message_unref (message);
- if (dbus_error_is_set (&error))
- {
- if (strcmp (error.name, "org.freedesktop.DBus.Error.UnknownMethod") != 0)
- nm_info ("Error from dhcdbd on 'reason' request because: name '%s', message '%s'.", error.name, error.message);
- dbus_error_free (&error);
+ /* Grab the device, if it exists... and set options for it (since as of
+ * now all interfaces are through the same dbus object)
+ */
+ iface = (char *) g_key_file_get_string (keyfile, "dhclient", "interface", NULL);
+ if (!iface) {
+ nm_warning ("Couldn't get dhclient interface from options.");
+ goto out;
}
- else if (reply)
- {
- if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID))
- state = 0;
- dbus_message_unref (reply);
+
+ device = (NMDHCPDevice *) g_hash_table_lookup (priv->devices, iface);
+ if (!device) {
+ nm_warning ("Interface %s not registered for DHCP", iface);
+ goto out;
+ }
+
+ nm_dhcp_device_timeout_cleanup (device);
+
+ keys = g_key_file_get_keys (keyfile, "dhclient", &length, NULL);
+ if (!keys) {
+ nm_warning ("Not enough memory for parsing dhclient options.");
+ goto out;
}
- return state;
+ for (i = 0; i < length; i++) {
+ char * key, * value;
+
+ key = g_strdup (keys[i]);
+ if (!key) {
+ nm_warning ("Not enough memory to parse dhclient option %s", keys[i]);
+ goto done_parse;
+ }
+
+ value = g_strdup (g_key_file_get_string (keyfile, "dhclient", key, NULL));
+ if (!key) {
+ nm_warning ("Not enough memory to parse dhclient option %s value.", keys[i]);
+ goto done_parse;
+ }
+
+ g_hash_table_insert (device->options, key, value);
+ if (strcmp (keys[i], "reason") == 0) {
+ guint32 old_state = device->state;
+ device->state = string_to_state (value);
+ nm_info ("DHCP: device %s state changed %s -> %s\n",
+ device->iface,
+ state_to_string (old_state),
+ state_to_string (device->state));
+ }
+ }
+
+done_parse:
+ g_strfreev (keys);
+
+ g_signal_emit (G_OBJECT (device->manager), signals[STATE_CHANGED], 0, device->iface, device->state);
+ success = TRUE;
+
+out:
+ if (keyfile)
+ g_key_file_free (keyfile);
+ return success;
}
-static guint32
-get_timeout_secs (NMActRequest *req)
+gboolean
+nm_dhcp_manager_process_signal (NMDHCPManager * manager,
+ DBusMessage *message)
{
- guint req_secs = nm_act_request_get_dhcp_timeout_wait (req);
- if (!req_secs)
- return NM_DHCP_TIMEOUT;
- return req_secs;
+ const char * method;
+ const char * path;
+
+ g_return_val_if_fail (message != NULL, FALSE);
+
+ method = dbus_message_get_member (message);
+ path = dbus_message_get_path (message);
+
+ if (strcmp ("Event", method) || strcmp (path, "/"))
+ return FALSE;
+
+ nm_dhcp_dbus_set_state (manager, message);
+ return TRUE;
}
+
+static NMDHCPManager *
+nm_dhcp_manager_new (NMData * data)
+{
+ NMDHCPManager *manager;
+ NMDHCPManagerPrivate *priv;
+
+ manager = g_object_new (NM_TYPE_DHCP_MANAGER, NULL);
+ priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
+
+ priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL,
+ (GDestroyNotify) nm_dhcp_device_destroy);
+ priv->data = data;
+
+ return manager;
+}
+
+
/*
* nm_dhcp_manager_handle_timeout
*
* Called after timeout of a DHCP transaction to notify device of the failure.
*
*/
-static gboolean nm_dhcp_manager_handle_timeout (NMActRequest *req)
+static gboolean
+nm_dhcp_manager_handle_timeout (gpointer user_data)
{
- NMData * data;
- NMDevice * dev;
-
- g_return_val_if_fail (req != NULL, FALSE);
-
- data = nm_act_request_get_data (req);
- g_assert (data);
-
- dev = nm_act_request_get_dev (req);
- g_assert (dev);
+ NMDHCPDevice *device = (NMDHCPDevice *) user_data;
nm_info ("Device '%s' DHCP transaction took too long (>%ds), stopping it.",
- nm_device_get_iface (dev), get_timeout_secs (req));
+ device->iface, NM_DHCP_TIMEOUT);
- if (nm_act_request_get_stage (req) == NM_ACT_STAGE_IP_CONFIG_START)
- {
- nm_act_request_set_dhcp_timeout (req, 0);
- nm_dhcp_manager_cancel_transaction (data->dhcp_manager, req);
- nm_device_activate_schedule_stage4_ip_config_timeout (req);
- }
+ g_signal_emit (G_OBJECT (device->manager), signals[TIMEOUT], 0, device->iface);
+
+ nm_dhcp_manager_cancel_transaction (device->manager, device->iface, FALSE);
return FALSE;
}
-
-gboolean nm_dhcp_manager_begin_transaction (NMDHCPManager *manager, NMActRequest *req)
+static NMDHCPDevice *
+nm_dhcp_device_new (NMDHCPManager *manager, const char *iface)
{
- DBusError error;
- DBusMessage * message;
- DBusMessage * reply;
- NMDevice * dev;
- char * path;
- const guint32 opt1 = 31; /* turns off ALL actions and dhclient-script just writes options to dhcdbd */
- const guint32 opt2 = 2; /* dhclient is run in ONE SHOT mode and releases existing leases when brought down */
- GSource * source;
+ NMDHCPDevice *device;
+ GHashTable * hash = NM_DHCP_MANAGER_GET_PRIVATE (manager)->devices;
- g_return_val_if_fail (manager != NULL, FALSE);
- g_return_val_if_fail (req != NULL, FALSE);
-
- if (!manager->running)
- {
- nm_warning ("dhcdbd not running!");
- return FALSE;
- }
- else
- {
- /* Cancel any DHCP transaction already in progress */
- nm_dhcp_manager_cancel_transaction (manager, req);
- /* FIXME don't sleep */
- sleep (1);
+ device = g_slice_new0 (NMDHCPDevice);
+ if (!device) {
+ nm_warning ("%s: Out of memory creating DHCP transaction object.", iface);
+ return NULL;
}
- dev = nm_act_request_get_dev (req);
- g_assert (dev);
-
- nm_info ("Activation (%s) Beginning DHCP transaction.", nm_device_get_iface (dev));
-
- path = g_strdup_printf (DHCP_OBJECT_PATH"/%s", nm_device_get_iface (dev));
- message = dbus_message_new_method_call (DHCP_SERVICE_NAME, path, DHCP_SERVICE_NAME, "up");
- g_free (path);
- if (message == NULL)
- {
- nm_warning ("nm_dhcp_manager_begin_transaction(): Couldn't allocate the dbus message");
- return FALSE;
+ device->iface = g_strdup (iface);
+ if (!device) {
+ nm_warning ("%s: Out of memory creating DHCP transaction object "
+ "property 'iface'.",
+ iface);
+ goto error;
}
-
- dbus_message_append_args (message, DBUS_TYPE_UINT32, &opt1, DBUS_TYPE_UINT32, &opt2, DBUS_TYPE_INVALID);
- dbus_error_init (&error);
- if ((reply = dbus_connection_send_with_reply_and_block (manager->data->dbus_connection, message, -1, &error)))
- dbus_message_unref (reply);
- dbus_message_unref (message);
- if (dbus_error_is_set (&error))
- {
- nm_info ("Couldn't send DHCP 'up' message because: name '%s', message '%s'.", error.name, error.message);
- dbus_error_free (&error);
- return FALSE;
+
+ device->manager = manager;
+
+ nm_dhcp_manager_cancel_transaction_real (device, FALSE);
+
+ /* Do this after the transaction cancel since that clears options out */
+ device->options = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_free);
+ if (!device->options) {
+ nm_warning ("%s: Out of memory creating DHCP transaction object "
+ "property 'options'.",
+ iface);
+ goto error;
}
- /* Set up a timeout on the transaction to kill it after NM_DHCP_TIMEOUT seconds */
- source = g_timeout_source_new (get_timeout_secs (req) * 1000);
- g_source_set_callback (source, (GSourceFunc) nm_dhcp_manager_handle_timeout, req, NULL);
- nm_act_request_set_dhcp_timeout (req, g_source_attach (source, manager->data->main_context));
- g_source_unref (source);
+ g_hash_table_insert (hash, device->iface, device);
+ return device;
- return TRUE;
+error:
+ g_hash_table_destroy (device->options);
+ g_free (device->iface);
+ g_slice_free (NMDHCPDevice, device);
+ return NULL;
}
-static void remove_timeout (NMDHCPManager *manager, NMActRequest *req)
+/*
+ * nm_dhcp_manager_get_option
+ *
+ * Return the requested dhcp item for the given interface
+ *
+ */
+static gpointer
+nm_dhcp_manager_get_option(NMDHCPDevice *device, const char *key)
{
- guint id;
-
- g_return_if_fail (manager != NULL);
- g_return_if_fail (req != NULL);
-
- /* Remove any pending timeouts on the request */
- if ((id = nm_act_request_get_dhcp_timeout (req)) > 0)
- {
- GSource * source = g_main_context_find_source_by_id (manager->data->main_context, id);
- nm_act_request_set_dhcp_timeout (req, 0);
- g_source_destroy (source);
- }
+ return g_hash_table_lookup (device->options, key);
}
+
/*
- * nm_dhcp_manager_cancel_transaction
+ * dhclient_watch_cb
*
- * Stop any in-progress DHCP transaction on a particular device.
+ * Watch our child dhclient process and get notified of events from it.
*
*/
-void nm_dhcp_manager_cancel_transaction (NMDHCPManager *manager, NMActRequest *req)
+static void dhclient_watch_cb (GPid pid, gint status, gpointer user_data)
{
- NMDevice *dev;
+ NMDHCPDevice *device = (NMDHCPDevice *)user_data;
- g_return_if_fail (manager != NULL);
- g_return_if_fail (req != NULL);
-
- dev = nm_act_request_get_dev (req);
- g_assert (dev);
+ if (!WIFEXITED (status)) {
+ device->state = DHC_ABEND;
+ nm_warning ("dhclient died abnormally");
+ }
+ device->dhclient_pid = 0;
- if (manager->running && !state_is_down (nm_act_request_get_dhcp_state (req)))
- {
- DBusMessage * message;
- char * path = g_strdup_printf (DHCP_OBJECT_PATH"/%s", nm_device_get_iface (dev));
-
- if ((message = dbus_message_new_method_call (DHCP_SERVICE_NAME, path, DHCP_SERVICE_NAME, "down")))
- {
- dbus_connection_send (manager->data->dbus_connection, message, NULL);
- dbus_message_unref (message);
-
- /* Give dhcdbd/dhclient some time to send out a RELEASE if they like */
- /* FIXME: we should really monitor the interface's DHCP state by waiting
- * for dhcdbd to tell us the device is "down" rather than sleeping here.
- */
- if (!manager->data->asleep)
- sleep (1);
- }
- g_free (path);
+ nm_dhcp_device_watch_cleanup (device);
+ nm_dhcp_device_timeout_cleanup (device);
- remove_timeout (manager, req);
- }
+ g_signal_emit (G_OBJECT (device->manager), signals[STATE_CHANGED], 0, device->iface, device->state);
}
-
-static gboolean get_ip4_uint32s (NMDHCPManager *manager, NMDevice *dev, const char *item,
- guint32 **ip4_uint32, guint32 *num_items, gboolean ignore_error)
+static gboolean
+dhclient_run (NMDHCPDevice *device, gchar *xtra_arg)
{
- DBusMessage * message = NULL;
- DBusMessage * reply = NULL;
- char * path;
+ const char ** dhclient_binary = NULL;
+ GPtrArray * dhclient_argv = NULL;
+ GPid pid;
+ GError * error = NULL;
+ char * pidfile = NULL;
gboolean success = FALSE;
+ NMDHCPManagerPrivate * priv;
+
+ /* Find dhclient */
+ dhclient_binary = dhclient_binary_paths;
+ while (*dhclient_binary != NULL) {
+ if (g_file_test (*dhclient_binary, G_FILE_TEST_EXISTS))
+ break;
+ dhclient_binary++;
+ }
- g_return_val_if_fail (manager != NULL, FALSE);
- g_return_val_if_fail (dev != NULL, FALSE);
- g_return_val_if_fail (ip4_uint32 != NULL, FALSE);
- g_return_val_if_fail (num_items != NULL, FALSE);
-
- *ip4_uint32 = NULL;
- *num_items = 0;
- path = g_strdup_printf (DHCP_OBJECT_PATH"/%s", nm_device_get_iface (dev));
- if ((message = dbus_message_new_method_call (DHCP_SERVICE_NAME, path, DHCP_SERVICE_NAME".dbus.get", item)))
- {
- DBusError error;
-
- dbus_error_init (&error);
- reply = dbus_connection_send_with_reply_and_block (manager->data->dbus_connection, message, -1, &error);
- if (reply)
- {
- GArray *buffer;
- DBusMessageIter iter;
-
- dbus_message_iter_init (reply, &iter);
-
- buffer = g_array_new (TRUE, TRUE, sizeof (guint32));
- while (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_UINT32)
- {
- guint32 value;
-
- dbus_message_iter_get_basic (&iter, &value);
- g_array_append_val (buffer, value);
- dbus_message_iter_next (&iter);
- success = TRUE;
- }
-
- if (success)
- {
- *ip4_uint32 = (guint32 *)(buffer->data);
- *num_items = buffer->len;
- }
- g_array_free (buffer, FALSE);
- dbus_message_unref (reply);
- }
+ if (!*dhclient_binary) {
+ nm_warning ("Could not find dhclient binary.");
+ goto out;
+ }
- if (dbus_error_is_set (&error))
- {
- if (!ignore_error)
- nm_warning ("get_ip4_uint32s(): error calling '%s', DHCP daemon returned error '%s', message '%s'.",
- item, error.name, error.message);
- dbus_error_free (&error);
- }
- dbus_message_unref (message);
+ pidfile = get_pidfile_for_iface (device->iface);
+ if (!pidfile) {
+ nm_warning ("%s: not enough memory for dhclient options.", device->iface);
+ goto out;
}
- g_free (path);
- return success;
-}
+ // FIXME: look for existing pidfile and kill dhclient
+ dhclient_argv = g_ptr_array_new ();
+ g_ptr_array_add (dhclient_argv, (gpointer) (*dhclient_binary));
-static gboolean get_ip4_string (NMDHCPManager *manager, NMDevice *dev, const char *item,
- char **string, gboolean ignore_error)
-{
- DBusMessage * message = NULL;
- DBusMessage * reply = NULL;
- char * path;
- gboolean success = FALSE;
+ g_ptr_array_add (dhclient_argv, (gpointer) "-d");
+ g_ptr_array_add (dhclient_argv, (gpointer) "-x");
- g_return_val_if_fail (manager != NULL, FALSE);
- g_return_val_if_fail (dev != NULL, FALSE);
- g_return_val_if_fail (string != NULL, FALSE);
+ if (xtra_arg != NULL)
+ g_ptr_array_add (dhclient_argv, (gpointer) xtra_arg);
- *string = NULL;
- path = g_strdup_printf (DHCP_OBJECT_PATH"/%s", nm_device_get_iface (dev));
- if ((message = dbus_message_new_method_call (DHCP_SERVICE_NAME, path, DHCP_SERVICE_NAME".dbus.get", item)))
- {
- DBusError error;
-
- dbus_error_init (&error);
- if ((reply = dbus_connection_send_with_reply_and_block (manager->data->dbus_connection, message, -1, &error)))
- {
- DBusMessageIter iter;
-
- dbus_message_iter_init (reply, &iter);
- if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING)
- {
- char *dbus_string;
-
- dbus_error_init (&error);
- if (dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &dbus_string, DBUS_TYPE_INVALID))
- {
- *string = g_strdup (dbus_string);
- success = TRUE;
- }
- }
- else if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_ARRAY)
- {
- char *byte_array = NULL;
- int len = 0;
-
- dbus_error_init (&error);
- if (dbus_message_get_args (reply, &error, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &byte_array, &len, DBUS_TYPE_INVALID))
- {
- byte_array[len] = '\0';
- *string = g_strdup (byte_array);
- success = TRUE;
- }
- }
- }
+ g_ptr_array_add (dhclient_argv, (gpointer) "-sf"); /* Set script file */
+ g_ptr_array_add (dhclient_argv, (gpointer) SYSCONFDIR "/NetworkManager/callouts/nm-dhcp-client.action" );
- if (dbus_error_is_set (&error))
- {
- if (!ignore_error)
- nm_warning ("get_ip4_string(): error calling '%s', DHCP daemon returned error '%s', message '%s'.",
- item, error.name, error.message);
- dbus_error_free (&error);
- *string = NULL;
- }
- dbus_message_unref (message);
+ g_ptr_array_add (dhclient_argv, (gpointer) "-pf"); /* Set pid file */
+ g_ptr_array_add (dhclient_argv, (gpointer) pidfile);
+
+ g_ptr_array_add (dhclient_argv, (gpointer) device->iface);
+ g_ptr_array_add (dhclient_argv, NULL);
+
+ if (!g_spawn_async (NULL, (char **) dhclient_argv->pdata, NULL,
+ G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error)) {
+ nm_warning ("dhclient failed to start. error: '%s'", error->message);
+ g_error_free (error);
+ goto out;
}
- g_free (path);
- return success;
-}
+ nm_info ("dhclient started with pid %d", pid);
+ device->dhclient_pid = pid;
+ device->watch_source = g_child_watch_source_new (pid);
+ g_source_set_callback (device->watch_source,
+ (GSourceFunc) dhclient_watch_cb,
+ device,
+ NULL);
-static gboolean nm_completion_dhcp_bound_test(int tries,
- nm_completion_args args)
-{
- NMActRequest * req = args[0];
- NMDevice * dev = args[1];
+ priv = NM_DHCP_MANAGER_GET_PRIVATE (device->manager);
+ g_source_attach (device->watch_source, priv->data->main_context);
+ success = TRUE;
- if (state_is_bound (nm_act_request_get_dhcp_state (req)))
- return TRUE;
- if (nm_device_activation_should_cancel (dev))
- return TRUE;
- return FALSE;
+out:
+ g_free (pidfile);
+ g_ptr_array_free (dhclient_argv, TRUE);
+ return success;
}
-/*
- * nm_dhcp_manager_get_ip4_config
- *
- * Get IP4 configuration values from the DHCP daemon
- *
- */
-NMIP4Config * nm_dhcp_manager_get_ip4_config (NMDHCPManager *manager, NMActRequest *req)
+gboolean
+nm_dhcp_manager_begin_transaction (NMDHCPManager *manager,
+ const char *iface,
+ guint32 timeout)
{
- NMDevice * dev;
- NMIP4Config * ip4_config = NULL;
- int i;
- guint32 count = 0;
- guint32 * ip4_address = NULL;
- guint32 * ip4_netmask = NULL;
- guint32 * ip4_broadcast = NULL;
- guint32 * ip4_nameservers = NULL;
- guint32 * ip4_gateway = NULL;
- guint32 num_ip4_nameservers = 0;
- guint32 num_ip4_nis_servers = 0;
- char * hostname = NULL;
- char * domain_names = NULL;
- char * nis_domain = NULL;
- guint32 * ip4_nis_servers = NULL;
- struct in_addr temp_addr;
- nm_completion_args args;
-
- g_return_val_if_fail (manager != NULL, NULL);
- g_return_val_if_fail (req != NULL, NULL);
-
- if (!manager->running)
- return NULL;
+ NMDHCPManagerPrivate *priv;
+ NMDHCPDevice *device;
- dev = nm_act_request_get_dev (req);
- g_assert (dev);
+ g_return_val_if_fail (NM_IS_DHCP_MANAGER (manager), FALSE);
+ g_return_val_if_fail (iface != NULL, FALSE);
- args[0] = req;
- args[1] = dev;
- nm_wait_for_completion (30, G_USEC_PER_SEC / 10,
- nm_completion_dhcp_bound_test, NULL, args);
- if (nm_device_activation_should_cancel (dev))
- return NULL;
+ priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
- if (!state_is_bound (nm_act_request_get_dhcp_state (req)))
- {
- nm_warning ("Tried to get IP4 Config for a device when dhcdbd wasn't in a BOUND state!");
- return NULL;
- }
+ device = (NMDHCPDevice *) g_hash_table_lookup (priv->devices, iface);
+ if (!device)
+ device = nm_dhcp_device_new (manager, iface);
- if (!get_ip4_uint32s (manager, dev, "ip_address", &ip4_address, &count, FALSE) || !count)
- goto out;
+ if (state_is_bound (device->state)) {
+ /* Cancel any DHCP transaction already in progress */
+ nm_dhcp_manager_cancel_transaction_real (device, TRUE);
+ }
- if (!get_ip4_uint32s (manager, dev, "subnet_mask", &ip4_netmask, &count, FALSE) || !count)
- goto out;
+ nm_info ("Activation (%s) Beginning DHCP transaction.", iface);
- if (!get_ip4_uint32s (manager, dev, "broadcast_address", &ip4_broadcast, &count, FALSE) || !count)
- goto out;
+ if (timeout == 0)
+ timeout = NM_DHCP_TIMEOUT;
- if (!get_ip4_uint32s (manager, dev, "routers", &ip4_gateway, &count, TRUE) || !count)
- {
- /* If DHCP doesn't have a 'routers', just use the DHCP server's address as our gateway for now */
- if (!get_ip4_uint32s (manager, dev, "dhcp_server_identifier", &ip4_gateway, &count, FALSE) || !count)
- goto out;
- }
+ /* Set up a timeout on the transaction to kill it after the timeout */
+ device->timeout_source = g_timeout_source_new (timeout * 1000);
+ g_source_set_callback (device->timeout_source,
+ nm_dhcp_manager_handle_timeout,
+ device,
+ NULL);
+ g_source_attach (device->timeout_source,
+ priv->data->main_context);
- get_ip4_string (manager, dev, "host_name", &hostname, TRUE);
- get_ip4_uint32s (manager, dev, "domain_name_servers", &ip4_nameservers, &num_ip4_nameservers, FALSE);
- get_ip4_string (manager, dev, "domain_name", &domain_names, TRUE);
- get_ip4_string (manager, dev, "nis_domain", &nis_domain, TRUE);
- get_ip4_uint32s (manager, dev, "nis_servers", &ip4_nis_servers, &num_ip4_nis_servers, TRUE);
+ dhclient_run (device, NULL);
- nm_info ("Retrieved the following IP4 configuration from the DHCP daemon:");
+ return TRUE;
+}
- ip4_config = nm_ip4_config_new ();
- nm_ip4_config_set_address (ip4_config, ip4_address[0]);
- temp_addr.s_addr = ip4_address[0];
- nm_info (" address %s", inet_ntoa (temp_addr));
+static void
+nm_dhcp_manager_cancel_transaction_real (NMDHCPDevice *device, gboolean blocking)
+{
+ int i = 20; /* 4 seconds */
+ char * pidfile;
- nm_ip4_config_set_netmask (ip4_config, ip4_netmask[0]);
- temp_addr.s_addr = ip4_netmask[0];
- nm_info (" netmask %s", inet_ntoa (temp_addr));
+ if (!device->dhclient_pid)
+ return;
- nm_ip4_config_set_broadcast (ip4_config, ip4_broadcast[0]);
- temp_addr.s_addr = ip4_broadcast[0];
- nm_info (" broadcast %s", inet_ntoa (temp_addr));
+ kill (device->dhclient_pid, SIGTERM);
- nm_ip4_config_set_gateway (ip4_config, ip4_gateway[0]);
- temp_addr.s_addr = ip4_gateway[0];
- nm_info (" gateway %s", inet_ntoa (temp_addr));
+ /* Yes, the state has to reach DHC_END. */
+ while (blocking && i-- > 0) {
+ gint child_status;
+ if (waitpid (device->dhclient_pid, &child_status, WNOHANG) > 0)
+ break;
+ g_usleep (G_USEC_PER_SEC / 5);
+ }
- for (i = 0; i < num_ip4_nameservers; i++)
- {
- nm_ip4_config_add_nameserver (ip4_config, ip4_nameservers[i]);
- temp_addr.s_addr = ip4_nameservers[i];
- nm_info (" nameserver %s", inet_ntoa (temp_addr));
+ if (i <= 0) {
+ nm_warning ("%s: dhclient pid %d didn't exit, will kill it.",
+ device->iface, device->dhclient_pid);
+ kill (device->dhclient_pid, SIGKILL);
}
- if (hostname)
- {
- nm_ip4_config_set_hostname (ip4_config, hostname);
- nm_info (" hostname '%s'", hostname);
+ /* Clean up the pidfile if it got left around */
+ pidfile = get_pidfile_for_iface (device->iface);
+ if (pidfile) {
+ remove (pidfile);
+ g_free (pidfile);
}
+ device->dhclient_pid = 0;
+ device->state = DHC_END;
- if (domain_names)
- {
- char **searches = g_strsplit (domain_names, " ", 0);
- char **s;
+ nm_dhcp_device_watch_cleanup (device);
+ nm_dhcp_device_timeout_cleanup (device);
+ g_hash_table_remove_all (device->options);
+}
- for (s = searches; *s; s++)
- {
- nm_info (" domain name '%s'", *s);
- nm_ip4_config_add_domain (ip4_config, *s);
- }
- g_strfreev (searches);
- }
- if (nis_domain)
- {
- nm_ip4_config_set_nis_domain (ip4_config, nis_domain);
- nm_info (" nis domain '%s'", nis_domain);
- }
+/*
+ * nm_dhcp_manager_cancel_transaction
+ *
+ * Stop any in-progress DHCP transaction on a particular device.
+ *
+ */
+void
+nm_dhcp_manager_cancel_transaction (NMDHCPManager *manager,
+ const char *iface,
+ gboolean blocking)
+{
+ NMDHCPDevice *device;
+ NMDHCPManagerPrivate *priv;
- for (i = 0; i < num_ip4_nis_servers; i++)
- {
- nm_ip4_config_add_nis_server (ip4_config, ip4_nis_servers[i]);
- temp_addr.s_addr = ip4_nis_servers[i];
- nm_info (" nis server %s", inet_ntoa (temp_addr));
- }
+ g_return_if_fail (NM_IS_DHCP_MANAGER (manager));
+ g_return_if_fail (iface != NULL);
- /*
- * Grab the MTU from the backend. If DHCP servers can send recommended MTU's,
- * should set that here if the backend returns zero.
- */
- nm_ip4_config_set_mtu (ip4_config, nm_system_get_mtu (dev));
+ priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
-out:
- g_free (hostname);
- g_free (domain_names);
- g_free (nis_domain);
+ device = (NMDHCPDevice *) g_hash_table_lookup (priv->devices, iface);
- g_free (ip4_address);
- g_free (ip4_netmask);
- g_free (ip4_broadcast);
- g_free (ip4_gateway);
- g_free (ip4_nameservers);
- g_free (ip4_nis_servers);
+ if (!device || !device->dhclient_pid)
+ return;
- return ip4_config;
+ nm_dhcp_manager_cancel_transaction_real (device, blocking);
}
-static inline const char * state_to_string (guint state)
+
+static gboolean
+handle_request_cancel (gpointer user_data)
{
- switch (state)
- {
- case DHCDBD_PREINIT:
- return "starting";
- case DHCDBD_BOUND:
- return "bound";
- case DHCDBD_RENEW:
- return "renew";
- case DHCDBD_REBOOT:
- return "reboot";
- case DHCDBD_REBIND:
- return "rebind";
- case DHCDBD_TIMEOUT:
- return "timeout";
- case DHCDBD_FAIL:
- return "fail";
- case DHCDBD_START:
- return "successfully started";
- case DHCDBD_ABEND:
- return "abnormal exit";
- case DHCDBD_END:
- return "normal exit";
- default:
- return "unknown";
- }
+ NMDHCPDevice *device = (NMDHCPDevice *) user_data;
+
+fprintf (stderr, "request_handle_cancel started...\n");
+ nm_dhcp_manager_cancel_transaction_real (device, TRUE);
+fprintf (stderr, "request_handle_cancel done.\n");
+fprintf (stderr, "%s: calling cancel_cleanup\n", __func__);
+ nm_dhcp_device_cancel_cleanup (device);
+ return FALSE;
}
+
/*
- * nm_dhcp_manager_process_signal
+ * nm_dhcp_manager_request_cancel_transaction
*
- * Possibly process a signal from the bus, if it comes from the currently
- * active DHCP daemon, if any. Return TRUE if processed, FALSE if not.
+ * Request that any in-progress transaction be canceled.
*
*/
-gboolean nm_dhcp_manager_process_signal (NMDHCPManager *manager, DBusMessage *message)
+void
+nm_dhcp_manager_request_cancel_transaction (NMDHCPManager *manager,
+ const char *iface,
+ gboolean blocking)
{
- const char * object_path;
- const char * member;
- const char * interface;
- gboolean handled = FALSE;
- NMDevice * dev;
- NMActRequest * req = NULL;
+ NMDHCPDevice *device;
+ NMDHCPManagerPrivate *priv;
- g_return_val_if_fail (manager != NULL, FALSE);
- g_return_val_if_fail (message != NULL, FALSE);
+ g_return_if_fail (NM_IS_DHCP_MANAGER (manager));
+ g_return_if_fail (iface != NULL);
- if (!(object_path = dbus_message_get_path (message)))
- return FALSE;
- if (!(member = dbus_message_get_member (message)))
- return FALSE;
- if (!(interface = dbus_message_get_interface (message)))
- return FALSE;
- /* Ignore non-DHCP related messages */
- if (strncmp (interface, DHCP_SERVICE_NAME, manager->dhcp_sn_len))
- return FALSE;
+ priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
-#if 0
- {
- const char *signature = dbus_message_get_signature (message);
- nm_info ("nm_dhcp_manager_process_signal(): got signal op='%s' member='%s' interface='%s' sig='%s'", object_path, member, interface, signature);
- }
-#endif
+ device = (NMDHCPDevice *) g_hash_table_lookup (priv->devices, iface);
- dev = nm_get_device_by_iface (manager->data, member);
- if (dev && (req = nm_device_get_act_request (dev)))
- {
- const char *iface = nm_device_get_iface (dev);
-
- if (dbus_message_is_signal (message, DHCP_SERVICE_NAME".state", iface))
- {
- guint8 state;
-
- if (dbus_message_get_args (message, NULL, DBUS_TYPE_BYTE, &state, DBUS_TYPE_INVALID))
- {
- const char *desc = state_to_string (state);
-
- nm_info ("DHCP daemon state is now %d (%s) for interface %s", state, desc, iface);
- switch (state)
- {
- case DHCDBD_BOUND: /* lease obtained */
- case DHCDBD_RENEW: /* lease renewed */
- case DHCDBD_REBOOT: /* have valid lease, but now obtained a different one */
- case DHCDBD_REBIND: /* new, different lease */
- if (nm_act_request_get_stage (req) == NM_ACT_STAGE_IP_CONFIG_START)
- {
- nm_device_activate_schedule_stage4_ip_config_get (req);
- remove_timeout (manager, req);
- }
- break;
-
- case DHCDBD_TIMEOUT: /* timed out contacting DHCP server */
- if (nm_act_request_get_stage (req) == NM_ACT_STAGE_IP_CONFIG_START)
- {
- nm_device_activate_schedule_stage4_ip_config_timeout (req);
- remove_timeout (manager, req);
- }
- break;
-
- case DHCDBD_FAIL: /* all attempts to contact server timed out, sleeping */
- case DHCDBD_ABEND: /* dhclient exited abnormally */
-// case DHCDBD_END: /* dhclient exited normally */
- if (nm_act_request_get_stage (req) == NM_ACT_STAGE_IP_CONFIG_START)
- {
- nm_policy_schedule_activation_failed (req);
- remove_timeout (manager, req);
- }
- break;
-
- default:
- break;
- }
- nm_act_request_set_dhcp_state (req, state);
- }
-
- handled = TRUE;
- }
+ if (!device || !device->dhclient_pid)
+ return;
+
+ if (!device->cancel_source) {
+ device->cancel_source = g_idle_source_new ();
+fprintf (stderr, "%s: created cancel source %p\n", __func__, device->cancel_source);
+ g_source_set_priority (device->cancel_source, G_PRIORITY_HIGH_IDLE);
+ g_source_set_callback (device->cancel_source,
+ handle_request_cancel,
+ device,
+ NULL);
+ g_source_attach (device->cancel_source,
+ priv->data->main_context);
}
- return handled;
+ while (blocking && device->cancel_source)
+ g_usleep (G_USEC_PER_SEC / 10);
}
/*
- * nm_dhcp_manager_process_name_owner_changed
+ * nm_dhcp_manager_get_ip4_config
*
- * Respond to "service created"/"service deleted" signals from dbus for the active DHCP daemon.
+ * Get IP4 configuration values from the DHCP daemon
*
*/
-gboolean nm_dhcp_manager_process_name_owner_changed (NMDHCPManager *manager, const char *changed_service_name, const char *old_owner, const char *new_owner)
+NMIP4Config *
+nm_dhcp_manager_get_ip4_config (NMDHCPManager *manager,
+ const char *iface)
{
- gboolean handled = FALSE;
- gboolean old_owner_good = (old_owner && strlen (old_owner));
- gboolean new_owner_good = (new_owner && strlen (new_owner));
+ NMDHCPManagerPrivate *priv;
+ NMDHCPDevice *device;
+ NMIP4Config * ip4_config = NULL;
+ guint32 ip4_address = 0;
+ guint32 ip4_netmask = 0;
+ guint32 ip4_broadcast = 0;
+ guint32 ip4_gateway = 0;
+ char * hostname = NULL;
+ char * domain_names = NULL;
+ char * nameservers = NULL;
+ char * nis_domain = NULL;
+ char * nis_servers = NULL;
+ char * ip = NULL; //this is a general string that is used as a temporary place for ip(s)
+
+ g_return_val_if_fail (NM_IS_DHCP_MANAGER (manager), NULL);
+ g_return_val_if_fail (iface != NULL, NULL);
+
+ priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
+
+ device = (NMDHCPDevice *) g_hash_table_lookup (priv->devices, iface);
+ if (!device) {
+ nm_warning ("Device '%s' transaction not started.", iface);
+ return NULL;
+ }
- g_return_val_if_fail (manager != NULL, FALSE);
- g_return_val_if_fail (changed_service_name != NULL, FALSE);
+ if (!state_is_bound (device->state)) {
+ nm_warning ("%s: dhclient didn't bind to a lease.", device->iface);
+ return NULL;
+ }
- /* Can't handle the signal if its not from the DHCP service */
- if (strcmp (DHCP_SERVICE_NAME, changed_service_name) != 0)
- return FALSE;
+ if (!state_is_bound (device->state)) {
+ nm_warning ("Tried to get IP4 Config for a device when DHCP "
+ "wasn't in a BOUND state!");
+ return NULL;
+ }
- if (!old_owner_good && new_owner_good)
- {
- char *match = get_dhcp_match_string (new_owner);
+ ip = g_hash_table_lookup (device->options, "new_ip_address");
+ if (ip != NULL) {
+ ip4_address = inet_addr (ip);
+ nm_info(" address %s", ip);
+ }
+ else {
+ return NULL;
+ }
- /* DHCP service got created */
- dbus_bus_add_match (manager->data->dbus_connection, match, NULL);
- g_free (match);
+ ip = g_hash_table_lookup (device->options, "new_subnet_mask");
+ if (ip != NULL) {
+ ip4_netmask = inet_addr (ip);
+ nm_info(" netmask %s", ip);
+ }
+ else {
+ return NULL;
+ }
- manager->running = TRUE;
- handled = TRUE;
+ ip = g_hash_table_lookup (device->options, "new_broadcast_address");
+ if (ip != NULL) {
+ ip4_broadcast = inet_addr (ip);
+ nm_info(" broadcast %s", ip);
}
- else if (old_owner_good && !new_owner_good)
- {
- char *match = get_dhcp_match_string (old_owner);
+ else {
+ return NULL;
+ }
+
+ ip = g_hash_table_lookup (device->options, "new_routers");
+ if (ip != NULL) {
+ ip4_gateway = inet_addr (ip);
+ }
+ else { /* If DHCP doesn't have a 'routers', just use the DHCP server's address as our gateway for now */
+ ip = g_hash_table_lookup (device->options, "new_dhcp_server_identifier");
+ if (ip != NULL)
+ ip4_gateway = inet_addr (ip);
+ else
+ return NULL;
+ }
+
+ nm_info(" gateway %s", ip);
- /* DHCP service went away */
- dbus_bus_remove_match (manager->data->dbus_connection, match, NULL);
- g_free (match);
+ ip4_config = nm_ip4_config_new ();
+ nm_ip4_config_set_address (ip4_config, ip4_address);
+ nm_ip4_config_set_netmask (ip4_config, ip4_netmask);
+ nm_ip4_config_set_broadcast (ip4_config, ip4_broadcast);
+ nm_ip4_config_set_gateway (ip4_config, ip4_gateway);
+
+ hostname = g_hash_table_lookup (device->options, "new_host_name");
+ nameservers = g_hash_table_lookup (device->options, "new_domain_name_servers");
+ domain_names = g_hash_table_lookup (device->options, "new_domain_name");
+ nis_domain = g_hash_table_lookup (device->options, "new_nis_domain");
+ nis_servers = g_hash_table_lookup (device->options, "new_nis_servers");
+
+
+ if (nameservers) {
+ char **searches = g_strsplit (nameservers, " ", 0);
+ char **s;
+ int ip4_nameserver;
- manager->running = FALSE;
- handled = TRUE;
+ for (s = searches; *s; s++) {
+ ip4_nameserver = inet_addr (*s);
+ nm_ip4_config_add_nameserver (ip4_config, ip4_nameserver);
+ nm_info (" nameserver '%s'", *s);
+ }
+ g_strfreev (searches);
}
- return handled;
-}
+ if (hostname) {
+ nm_ip4_config_set_hostname (ip4_config, hostname);
+ nm_info (" hostname '%s'", hostname);
+ }
+ if (domain_names) {
+ char **searches = g_strsplit (domain_names, " ", 0);
+ char **s;
+ for (s = searches; *s; s++) {
+ nm_info (" domain name '%s'", *s);
+ nm_ip4_config_add_domain (ip4_config, *s);
+ }
+ g_strfreev (searches);
+ }
+
+ if (nis_domain) {
+ nm_ip4_config_set_nis_domain (ip4_config, nis_domain);
+ nm_info (" nis domain '%s'", nis_domain);
+ }
+
+ if (nis_servers) {
+ char **searches = g_strsplit (nis_servers, " ", 0);
+ char **s;
+ int ip4_nis_server;
+
+ for (s = searches; *s; s++) {
+ ip4_nis_server = inet_addr (*s);
+ nm_ip4_config_add_nis_server (ip4_config, ip4_nis_server);
+ nm_info (" nis server '%s'", *s);
+ }
+ g_strfreev (searches);
+ }
+
+ /*
+ * FIXME:
+ * Grab the MTU from the backend. If DHCP servers can send recommended
+ * MTU's, should set that here.
+ */
+
+ return ip4_config;
+}
diff --git a/src/dhcp-manager/nm-dhcp-manager.h b/src/dhcp-manager/nm-dhcp-manager.h
index 2746713bed..1c002bae2d 100644
--- a/src/dhcp-manager/nm-dhcp-manager.h
+++ b/src/dhcp-manager/nm-dhcp-manager.h
@@ -21,47 +21,72 @@
#ifndef NM_DHCP_MANAGER_H
#define NM_DHCP_MANAGER_H
-#include "NetworkManagerMain.h"
-#include "nm-device.h"
+#include <glib/gtypes.h>
+#include <glib-object.h>
+#include "nm-ip4-config.h"
-/*
- * FIXME: These should go in a header shared by NetworkManager and dhcdbd,
- * but right now NetworkManager and dhcdbd do not share any header. The
- * following is copied (and cleaned up) from dhcdbd.h.
- */
-enum dhcdbd_state
-{
- DHCDBD_NBI=0, /* no broadcast interfaces found */
- DHCDBD_PREINIT, /* configuration started */
- DHCDBD_BOUND, /* lease obtained */
- DHCDBD_RENEW, /* lease renewed */
- DHCDBD_REBOOT, /* have valid lease, but now obtained a different one */
- DHCDBD_REBIND, /* new, different lease */
- DHCDBD_STOP, /* remove old lease */
- DHCDBD_MEDIUM, /* media selection begun */
- DHCDBD_TIMEOUT, /* timed out contacting DHCP server */
- DHCDBD_FAIL, /* all attempts to contact server timed out, sleeping */
- DHCDBD_EXPIRE, /* lease has expired, renewing */
- DHCDBD_RELEASE, /* releasing lease */
- DHCDBD_START, /* sent when dhclient started OK */
- DHCDBD_ABEND, /* dhclient exited abnormally */
- DHCDBD_END, /* dhclient exited normally */
- DHCDBD_END_OPTIONS, /* last option in subscription sent */
-};
+#define NM_TYPE_DHCP_MANAGER (nm_dhcp_manager_get_type ())
+#define NM_DHCP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_MANAGER, NMDHCPManager))
+#define NM_DHCP_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DHCP_MANAGER, NMDHCPManagerClass))
+#define NM_IS_DHCP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DHCP_MANAGER))
+#define NM_IS_DHCP_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_DHCP_MANAGER))
+#define NM_DHCP_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP_MANAGER, NMDHCPManagerClass))
+
+#define NM_DHCP_MANAGER_PID_DIR "/var/run"
+#define NM_DHCP_MANAGER_PID_FILENAME "dhclient"
+#define NM_DHCP_MANAGER_PID_FILE_EXT "pid"
+
+#define DHCP_CALLOUT_INTERFACE "org.freedesktop.nm_dhcp_client"
+
+typedef enum {
+ DHC_NBI=0, /* no broadcast interfaces found */
+ DHC_PREINIT, /* configuration started */
+ DHC_BOUND, /* lease obtained */
+ DHC_RENEW, /* lease renewed */
+ DHC_REBOOT, /* have valid lease, but now obtained a different one */
+ DHC_REBIND, /* new, different lease */
+ DHC_STOP, /* remove old lease */
+ DHC_MEDIUM, /* media selection begun */
+ DHC_TIMEOUT, /* timed out contacting DHCP server */
+ DHC_FAIL, /* all attempts to contact server timed out, sleeping */
+ DHC_EXPIRE, /* lease has expired, renewing */
+ DHC_RELEASE, /* releasing lease */
+ DHC_START, /* sent when dhclient started OK */
+ DHC_ABEND, /* dhclient exited abnormally */
+ DHC_END, /* dhclient exited normally */
+ DHC_END_OPTIONS, /* last option in subscription sent */
+} NMDHCPState;
+
+typedef struct {
+ GObject parent;
+} NMDHCPManager;
+
+typedef struct {
+ GObjectClass parent;
-char * get_dhcp_match_string (const char *owner);
+ /* Signals */
+ void (*state_changed) (NMDHCPManager *manager, char *iface, NMDHCPState state);
+ void (*timeout) (NMDHCPManager *manager, char *iface);
+} NMDHCPManagerClass;
-NMDHCPManager * nm_dhcp_manager_new (NMData *data);
-void nm_dhcp_manager_dispose (NMDHCPManager *manager);
+struct NMData;
-gboolean nm_dhcp_manager_begin_transaction (NMDHCPManager *manager, NMActRequest *req);
-void nm_dhcp_manager_cancel_transaction (NMDHCPManager *manager, NMActRequest *req);
+GType nm_dhcp_manager_get_type (void);
-NMIP4Config * nm_dhcp_manager_get_ip4_config (NMDHCPManager *manager, NMActRequest *req);
+NMDHCPManager *nm_dhcp_manager_get (struct NMData * data);
+gboolean nm_dhcp_manager_begin_transaction (NMDHCPManager *manager,
+ const char *iface,
+ guint32 timeout);
+void nm_dhcp_manager_cancel_transaction (NMDHCPManager *manager,
+ const char *iface,
+ gboolean blocking);
+NMIP4Config * nm_dhcp_manager_get_ip4_config (NMDHCPManager *manager, const char *iface);
+NMDHCPState nm_dhcp_manager_get_state_for_device (NMDHCPManager *manager, const char *iface);
-gboolean nm_dhcp_manager_process_signal (NMDHCPManager *manager, DBusMessage *message);
-gboolean nm_dhcp_manager_process_name_owner_changed (NMDHCPManager *manager, const char *changed_service_name, const char *old_owner, const char *new_owner);
+gboolean nm_dhcp_manager_process_signal (NMDHCPManager *manager, DBusMessage *message);
-guint32 nm_dhcp_manager_get_state_for_device (NMDHCPManager *manager, NMDevice *dev);
+void nm_dhcp_manager_request_cancel_transaction (NMDHCPManager *manager,
+ const char *iface,
+ gboolean blocking);
-#endif
+#endif /* NM_DHCP_MANAGER_H */
diff --git a/src/dhcp-manager/nm-dhcp-marshal-main.c b/src/dhcp-manager/nm-dhcp-marshal-main.c
new file mode 100644
index 0000000000..eba68d7ea1
--- /dev/null
+++ b/src/dhcp-manager/nm-dhcp-marshal-main.c
@@ -0,0 +1,3 @@
+#include "nm-dhcp-marshal.h"
+#include "nm-dhcp-marshal.c"
+
diff --git a/src/dhcp-manager/nm-dhcp-marshal.list b/src/dhcp-manager/nm-dhcp-marshal.list
new file mode 100644
index 0000000000..8147399d30
--- /dev/null
+++ b/src/dhcp-manager/nm-dhcp-marshal.list
@@ -0,0 +1,2 @@
+VOID:STRING,UCHAR
+
diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c
index 4f25b07c29..e563d2b3f4 100644
--- a/src/nm-activation-request.c
+++ b/src/nm-activation-request.c
@@ -43,8 +43,6 @@ struct NMActRequest
NMActStage stage;
DBusPendingCall * user_key_pcall;
- guint32 dhcp_state;
- guint dhcp_timeout; /* the timeout source itself */
guint dhcp_timeout_wait; /* in seconds */
};
@@ -71,7 +69,6 @@ NMActRequest * nm_act_request_new (NMData *data, NMDevice *dev, NMAccessPoint *a
req->ap = ap;
req->user_requested = user_requested;
- req->dhcp_state = nm_dhcp_manager_get_state_for_device (data->dhcp_manager, dev);
return req;
}
@@ -98,12 +95,6 @@ void nm_act_request_unref (NMActRequest *req)
if (req->ip4_config)
nm_ip4_config_unref (req->ip4_config);
- if (req->dhcp_timeout > 0)
- {
- GSource * source = g_main_context_find_source_by_id (req->data->main_context, req->dhcp_timeout);
- g_source_destroy (source);
- }
-
memset (req, 0, sizeof (NMActRequest));
g_free (req);
}
@@ -216,34 +207,6 @@ void nm_act_request_set_user_key_pending_call (NMActRequest *req, DBusPendingCal
req->user_key_pcall = pcall;
}
-guint8 nm_act_request_get_dhcp_state (NMActRequest *req)
-{
- g_return_val_if_fail (req != NULL, 0);
-
- return req->dhcp_state;
-}
-
-void nm_act_request_set_dhcp_state (NMActRequest *req, guint8 dhcp_state)
-{
- g_return_if_fail (req != NULL);
-
- req->dhcp_state = dhcp_state;
-}
-
-guint nm_act_request_get_dhcp_timeout (NMActRequest *req)
-{
- g_return_val_if_fail (req != NULL, 0);
-
- return req->dhcp_timeout;
-}
-
-void nm_act_request_set_dhcp_timeout (NMActRequest *req, guint dhcp_timeout)
-{
- g_return_if_fail (req != NULL);
-
- req->dhcp_timeout = dhcp_timeout;
-}
-
guint nm_act_request_get_dhcp_timeout_wait (NMActRequest *req)
{
g_return_val_if_fail (req != NULL, 0);
diff --git a/src/nm-activation-request.h b/src/nm-activation-request.h
index c5579fa432..5f9f747238 100644
--- a/src/nm-activation-request.h
+++ b/src/nm-activation-request.h
@@ -50,12 +50,6 @@ void nm_act_request_set_stage (NMActRequest *req, NMActStage stage);
DBusPendingCall * nm_act_request_get_user_key_pending_call (NMActRequest *req);
void nm_act_request_set_user_key_pending_call (NMActRequest *req, DBusPendingCall *pcall);
-guint8 nm_act_request_get_dhcp_state (NMActRequest *req);
-void nm_act_request_set_dhcp_state (NMActRequest *req, guint8 dhcp_state);
-
-guint nm_act_request_get_dhcp_timeout (NMActRequest *req);
-void nm_act_request_set_dhcp_timeout (NMActRequest *req, guint dhcp_timeout);
-
guint nm_act_request_get_dhcp_timeout_wait (NMActRequest *req);
void nm_act_request_set_dhcp_timeout_wait (NMActRequest *req, guint dhcp_timeout);
diff --git a/src/nm-device-802-11-mesh-olpc.c b/src/nm-device-802-11-mesh-olpc.c
index 077067888c..6a80b5e6a2 100644
--- a/src/nm-device-802-11-mesh-olpc.c
+++ b/src/nm-device-802-11-mesh-olpc.c
@@ -38,6 +38,7 @@
#include "nm-activation-request.h"
#include "NetworkManagerSystem.h"
#include "NetworkManagerPolicy.h"
+#include "nm-dhcp-manager.h"
#define MESH_SSID "olpc-mesh"
#define MPP_DEFAULT_CHANNEL 1
@@ -349,7 +350,8 @@ real_init (NMDevice *dev)
g_direct_equal);
if ( !self->priv->mpp.activated_ids
|| !self->priv->mpp.deactivated_ids) {
- nm_warning ("%s: couldn't allocate MPP tables.");
+ nm_warning ("%s: couldn't allocate MPP tables.",
+ nm_device_get_iface (NM_DEVICE (self)));
mpp_clear_hash_tables (self);
}
@@ -504,7 +506,7 @@ cleanup_ethdev (NMDevice80211MeshOLPC *self)
static void
connect_to_device_signals (NMDevice80211MeshOLPC *self, NMDevice *dev)
{
- guint32 act_id, deact_id, act_fail_id;
+ guint32 act_id, deact_id;
g_return_if_fail (self != NULL);
g_return_if_fail (dev != NULL);
@@ -668,7 +670,7 @@ real_notify_device_removed (NMDevice *dev,
/* If we are an MPP and the removed device was the one providing
* the primary connection, stop being an MPP.
*/
- if (removed_dev = self->priv->mpp.primary)
+ if (removed_dev == self->priv->mpp.primary)
mpp_cleanup (self);
}
@@ -1001,8 +1003,6 @@ is_mpp_active (NMDevice80211MeshOLPC *self)
static void
mpp_cleanup (NMDevice80211MeshOLPC *self)
{
- NMIP4Config * config;
-
if (self->priv->mpp.primary) {
NMData * data = nm_device_get_app_data (NM_DEVICE (self));
if (self->priv->mpp.associated) {
@@ -1205,7 +1205,6 @@ aipd_watch_cb (GPid pid,
gpointer user_data)
{
NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (user_data);
- NMDevice * dev = NM_DEVICE (user_data);
g_assert (self);
@@ -1319,7 +1318,6 @@ static gboolean
aipd_monitor_start (NMDevice80211MeshOLPC *self)
{
gboolean success = FALSE;
- GIOChannel * channel;
GMainContext * context;
g_return_val_if_fail (self != NULL, FALSE);
@@ -1640,7 +1638,7 @@ real_act_stage4_get_ip4_config (NMDevice *dev,
NMDevice80211MeshOLPCClass * klass;
NMDeviceClass * parent_class;
const char * iface = nm_device_get_iface (dev);
- NMData * data = nm_device_get_app_data (dev);
+ NMDHCPManager * dhcp_manager = nm_dhcp_manager_get (NULL);
g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE);
g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE);
@@ -1662,13 +1660,18 @@ real_act_stage4_get_ip4_config (NMDevice *dev,
/* Kill dhclient; we don't need it anymore after MPP discovery here
* because we're ignoring the returned lease.
*/
- nm_dhcp_manager_cancel_transaction (data->dhcp_manager, req);
- sleep (1);
+ nm_dhcp_manager_request_cancel_transaction (dhcp_manager,
+ nm_device_get_iface (NM_DEVICE (self)),
+ TRUE);
if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
goto out;
break;
case MESH_S4_P2P_MESH:
real_config = nm_ip4_config_new ();
+ if (!real_config) {
+ nm_warning ("Not enough memory to create ip4 config.");
+ goto out;
+ }
nm_ip4_config_set_address (real_config, self->priv->aipd.ip4_addr);
nm_ip4_config_set_netmask (real_config, (guint32)(ntohl (IPV4LL_NETMASK)));
nm_ip4_config_set_broadcast (real_config, (guint32)(ntohl (IPV4LL_BROADCAST)));
diff --git a/src/nm-device.c b/src/nm-device.c
index 2518910749..3e912229a4 100644
--- a/src/nm-device.c
+++ b/src/nm-device.c
@@ -77,13 +77,16 @@ struct _NMDevicePrivate
/* IP configuration info */
void * system_config_data; /* Distro-specific config data (parsed config file, etc) */
- gboolean use_dhcp;
NMIP4Config * ip4_config; /* Config from DHCP, PPP, or system config files */
GMainContext * context;
GMainLoop * loop;
GThread * worker;
gboolean worker_started;
+
+ NMDHCPManager * dhcp_manager;
+ gulong dhcp_state_sigid;
+ gulong dhcp_timeout_sigid;
};
static gpointer nm_device_worker (gpointer user_data);
@@ -214,7 +217,6 @@ nm_device_new (const char *iface,
/* Grab IP config data for this device from the system configuration files */
dev->priv->system_config_data = nm_system_device_get_system_config (dev, app_data);
- dev->priv->use_dhcp = nm_system_device_get_use_dhcp (dev);
/* Allow distributions to flag devices as disabled */
if (nm_system_device_get_disabled (dev))
@@ -271,7 +273,6 @@ nm_device_init (NMDevice * self)
self->priv->quit_activation = FALSE;
self->priv->system_config_data = NULL;
- self->priv->use_dhcp = TRUE;
self->priv->ip4_config = NULL;
self->priv->context = NULL;
@@ -911,22 +912,34 @@ real_act_stage3_ip_config_start (NMDevice *self,
nm_device_bring_up (self);
/* DHCP devices try DHCP, non-DHCP default to SUCCESS */
- if (nm_device_get_use_dhcp (self))
- {
- /* Begin a DHCP transaction on the interface */
- if (!nm_dhcp_manager_begin_transaction (data->dhcp_manager, req))
- {
+ if (nm_system_device_get_use_dhcp (self)) {
+ gboolean success;
+ guint32 timeout;
+
+ nm_device_set_use_dhcp (self, TRUE);
+
+ /* DHCP manager will cancel any transaction already in progress and we do not
+ want to cancel this activation if we get "down" state from that. */
+ g_signal_handler_block (self->priv->dhcp_manager,
+ self->priv->dhcp_state_sigid);
+
+ timeout = nm_act_request_get_dhcp_timeout_wait (req);
+ success = nm_dhcp_manager_begin_transaction (self->priv->dhcp_manager,
+ nm_device_get_iface (self),
+ timeout);
+
+ g_signal_handler_unblock (self->priv->dhcp_manager,
+ self->priv->dhcp_state_sigid);
+
+ if (success) {
+ /* DHCP devices will be notified by the DHCP manager when
+ * stuff happens.
+ */
+ ret = NM_ACT_STAGE_RETURN_POSTPONE;
+ } else
ret = NM_ACT_STAGE_RETURN_FAILURE;
- goto out;
- }
-
- /* DHCP devices will be notified by the DHCP manager when
- * stuff happens.
- */
- ret = NM_ACT_STAGE_RETURN_POSTPONE;
}
-out:
return ret;
}
@@ -1053,10 +1066,16 @@ real_act_stage4_get_ip4_config (NMDevice *self,
data = nm_act_request_get_data (req);
g_assert (data);
- if (nm_device_get_use_dhcp (self))
- real_config = nm_dhcp_manager_get_ip4_config (data->dhcp_manager, req);
- else
+ if (nm_device_get_use_dhcp (self)) {
+ real_config = nm_dhcp_manager_get_ip4_config (NM_DEVICE_GET_PRIVATE (self)->dhcp_manager,
+ nm_device_get_iface (self));
+
+ if (real_config && nm_ip4_config_get_mtu (real_config) == 0)
+ /* If the DHCP server doesn't set the MTU, get it from backend. */
+ nm_ip4_config_set_mtu (real_config, nm_system_get_mtu (self));
+ } else {
real_config = nm_system_device_new_ip4_system_config (self);
+ }
if (real_config)
{
@@ -1340,9 +1359,6 @@ real_activation_cancel_handler (NMDevice *self,
{
g_return_if_fail (self != NULL);
g_return_if_fail (req != NULL);
-
- if (nm_act_request_get_stage (req) == NM_ACT_STAGE_IP_CONFIG_START)
- nm_dhcp_manager_cancel_transaction (self->priv->app_data->dhcp_manager, req);
}
/*
@@ -1495,12 +1511,19 @@ nm_device_deactivate_quickly (NMDevice *self)
else if (nm_device_is_activating (self))
nm_device_activation_cancel (self);
+ if (nm_device_get_use_dhcp (self)) {
+ fprintf (stderr, "will cancel DHCP\n");
+ nm_dhcp_manager_request_cancel_transaction (NM_DEVICE_GET_PRIVATE (self)->dhcp_manager,
+ nm_device_get_iface (self),
+ FALSE);
+ fprintf (stderr, "... done\n");
+ }
+
/* Tear down an existing activation request, which may not have happened
* in nm_device_activation_cancel() above, for various reasons.
*/
if ((act_request = nm_device_get_act_request (self)))
{
- nm_dhcp_manager_cancel_transaction (app_data->dhcp_manager, act_request);
nm_act_request_unref (act_request);
self->priv->act_request = NULL;
}
@@ -1694,12 +1717,74 @@ nm_device_can_interrupt_activation (NMDevice *self)
/* IP Configuration stuff */
+static void
+dhcp_state_changed (NMDHCPManager *dhcp_manager,
+ const char *iface,
+ NMDHCPState state,
+ gpointer user_data)
+{
+ NMDevice * self = NM_DEVICE (user_data);
+ NMActRequest * req;
+
+ if (strcmp (nm_device_get_iface (self), iface) != 0)
+ return;
+
+ req = nm_device_get_act_request (self);
+ g_return_if_fail (req != NULL);
+
+ switch (state) {
+ case DHC_BOUND: /* lease obtained */
+ case DHC_RENEW: /* lease renewed */
+ case DHC_REBOOT: /* have valid lease, but now obtained a different one */
+ case DHC_REBIND: /* new, different lease */
+ if (nm_act_request_get_stage (req) == NM_ACT_STAGE_IP_CONFIG_START)
+ nm_device_activate_schedule_stage4_ip_config_get (req);
+ break;
+ case DHC_TIMEOUT: /* timed out contacting DHCP server */
+ if (nm_act_request_get_stage (req) == NM_ACT_STAGE_IP_CONFIG_START)
+ nm_device_activate_schedule_stage4_ip_config_timeout (req);
+ break;
+ case DHC_FAIL: /* all attempts to contact server timed out, sleeping */
+ case DHC_ABEND: /* dhclient exited abnormally */
+ case DHC_END: /* dhclient exited normally */
+ if (nm_act_request_get_stage (req) == NM_ACT_STAGE_IP_CONFIG_START) {
+ nm_policy_schedule_activation_failed (req);
+ } else if (nm_device_is_activated (self)) {
+ if (nm_device_get_use_dhcp (self)) {
+ /* dhclient quit and therefore can't renew our lease, kill the conneciton */
+ nm_policy_schedule_deactivate (self);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+dhcp_timeout (NMDHCPManager *dhcp_manager,
+ const char *iface,
+ gpointer user_data)
+{
+ NMDevice * self = NM_DEVICE (user_data);
+ NMActRequest * req;
+
+ if (strcmp (nm_device_get_iface (self), iface) != 0)
+ return;
+
+ req = nm_device_get_act_request (self);
+ g_return_if_fail (req != NULL);
+
+ if (nm_act_request_get_stage (req) == NM_ACT_STAGE_IP_CONFIG_START)
+ nm_device_activate_schedule_stage4_ip_config_timeout (req);
+}
+
gboolean
nm_device_get_use_dhcp (NMDevice *self)
{
g_return_val_if_fail (self != NULL, FALSE);
- return self->priv->use_dhcp;
+ return self->priv->dhcp_manager ? TRUE : FALSE;
}
void
@@ -1708,7 +1793,30 @@ nm_device_set_use_dhcp (NMDevice *self,
{
g_return_if_fail (self != NULL);
- self->priv->use_dhcp = use_dhcp;
+ if (use_dhcp) {
+ if (!self->priv->dhcp_manager) {
+ self->priv->dhcp_manager = nm_dhcp_manager_get (NULL);
+ self->priv->dhcp_state_sigid = g_signal_connect (self->priv->dhcp_manager,
+ "state-changed",
+ G_CALLBACK (dhcp_state_changed),
+ self);
+ self->priv->dhcp_timeout_sigid = g_signal_connect (self->priv->dhcp_manager,
+ "timeout",
+ G_CALLBACK (dhcp_timeout),
+ self);
+ }
+ } else if (self->priv->dhcp_manager) {
+ g_signal_handler_disconnect (self->priv->dhcp_manager,
+ self->priv->dhcp_state_sigid);
+ self->priv->dhcp_state_sigid = 0;
+
+ g_signal_handler_disconnect (self->priv->dhcp_manager,
+ self->priv->dhcp_timeout_sigid);
+ self->priv->dhcp_timeout_sigid = 0;
+
+ g_object_unref (self->priv->dhcp_manager);
+ self->priv->dhcp_manager = NULL;
+ }
}