about summary refs log tree commit diff
path: root/src/dhcp-manager
diff options
context:
space:
mode:
Diffstat (limited to 'src/dhcp-manager')
-rw-r--r--src/dhcp-manager/Makefile.am76
-rw-r--r--src/dhcp-manager/Makefile.in505
-rw-r--r--src/dhcp-manager/nm-dhcp-client.c424
-rw-r--r--src/dhcp-manager/nm-dhcp-client.h21
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient-utils.c313
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient-utils.h10
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient.c284
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient.h4
-rw-r--r--src/dhcp-manager/nm-dhcp-dhcpcd.c31
-rw-r--r--src/dhcp-manager/nm-dhcp-dhcpcd.h2
-rw-r--r--src/dhcp-manager/nm-dhcp-helper.c345
-rw-r--r--src/dhcp-manager/nm-dhcp-helper.conf13
-rw-r--r--src/dhcp-manager/nm-dhcp-manager.c380
-rw-r--r--src/dhcp-manager/nm-dhcp-manager.h24
-rw-r--r--src/dhcp-manager/tests/Makefile.am29
-rw-r--r--src/dhcp-manager/tests/Makefile.in214
-rw-r--r--src/dhcp-manager/tests/leases/basic.leases31
-rw-r--r--src/dhcp-manager/tests/leases/malformed1.leases15
-rw-r--r--src/dhcp-manager/tests/leases/malformed2.leases15
-rw-r--r--src/dhcp-manager/tests/leases/malformed3.leases15
-rw-r--r--src/dhcp-manager/tests/test-dhcp-dhclient.c237
21 files changed, 1853 insertions, 1135 deletions
diff --git a/src/dhcp-manager/Makefile.am b/src/dhcp-manager/Makefile.am
index f32a2167..63eac9d5 100644
--- a/src/dhcp-manager/Makefile.am
+++ b/src/dhcp-manager/Makefile.am
@@ -1,71 +1,23 @@
-SUBDIRS = . tests
+libexec_PROGRAMS = nm-dhcp-helper
 
-AM_CPPFLAGS = \
-	-I${top_srcdir} \
-	-I${top_builddir}/include \
-	-I${top_srcdir}/include \
-	-I${top_builddir}/src/generated \
-	-I${top_srcdir}/src/generated \
-	-I${top_srcdir}/src/logging \
-	-I${top_srcdir}/src/posix-signals \
-	-I${top_builddir}/libnm-util \
-	-I${top_srcdir}/libnm-util \
-	-I${top_srcdir}/src \
-	-DRUNDIR=\"$(rundir)\"
+nm_dhcp_helper_SOURCES = nm-dhcp-helper.c
 
-noinst_LTLIBRARIES = libdhcp-manager.la libdhcp-dhclient.la
-
-################## dhclient ##################
-
-libdhcp_dhclient_la_SOURCES = \
-	nm-dhcp-dhclient-utils.h \
-	nm-dhcp-dhclient-utils.c \
-	nm-dhcp-dhclient.h \
-	nm-dhcp-dhclient.c
-
-libdhcp_dhclient_la_CPPFLAGS = \
+nm_dhcp_helper_CPPFLAGS = \
 	$(DBUS_CFLAGS) \
-	$(GLIB_CFLAGS) \
-	$(AM_CPPFLAGS) \
-	-DSYSCONFDIR=\"$(sysconfdir)\" \
-	-DLIBEXECDIR=\"$(libexecdir)\" \
-	-DLOCALSTATEDIR=\"$(localstatedir)\" \
-	-DDHCLIENT_PATH=\"$(DHCLIENT_PATH)\" \
-	-DNMSTATEDIR=\"$(nmstatedir)\" \
-	-DNMCONFDIR=\"$(nmconfdir)\"
+	-DG_LOG_DOMAIN=\""nm-dhcp-helper"\" \
+	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+	-DNMRUNDIR=\"$(nmrundir)\"
 
-libdhcp_dhclient_la_LIBADD = \
-	$(top_builddir)/src/logging/libnm-logging.la \
-	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
-	$(top_builddir)/libnm-util/libnm-util.la \
-	$(DBUS_LIBS) \
-	$(GLIB_LIBS)
+nm_dhcp_helper_LDADD = $(DBUS_LIBS)
 
-################## main lib ##################
 
-libdhcp_manager_la_SOURCES = \
-	nm-dhcp-client.c \
-	nm-dhcp-client.h \
-	nm-dhcp-manager.c \
-	nm-dhcp-manager.h \
-	nm-dhcp-dhcpcd.h \
-	nm-dhcp-dhcpcd.c
+# FIXME: remove when dbus-glib >= 0.100 is required
+dhcp_helper_conf = nm-dhcp-helper.conf
 
-libdhcp_manager_la_CPPFLAGS = \
-	$(DBUS_CFLAGS) \
-	$(GLIB_CFLAGS) \
-	$(AM_CPPFLAGS) \
-	-DSYSCONFDIR=\"$(sysconfdir)\" \
-	-DLIBEXECDIR=\"$(libexecdir)\" \
-	-DLOCALSTATEDIR=\"$(localstatedir)\" \
-	-DDHCLIENT_PATH=\"$(DHCLIENT_PATH)\" \
-	-DDHCPCD_PATH=\"$(DHCPCD_PATH)\" \
-	-DNMSTATEDIR=\"$(nmstatedir)\"
+if !HAVE_DBUS_GLIB_100
+dbusservicedir = $(DBUS_SYS_DIR)
+dbusservice_DATA = $(dhcp_helper_conf)
+endif
 
-libdhcp_manager_la_LIBADD = \
-	$(top_builddir)/src/logging/libnm-logging.la \
-	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
-	$(builddir)/libdhcp-dhclient.la \
-	$(DBUS_LIBS) \
-	$(GLIB_LIBS)
+EXTRA_DIST = $(dhcp_helper_conf)
 
diff --git a/src/dhcp-manager/Makefile.in b/src/dhcp-manager/Makefile.in
index db4b0c91..5495b12f 100644
--- a/src/dhcp-manager/Makefile.in
+++ b/src/dhcp-manager/Makefile.in
@@ -14,6 +14,7 @@
 
 @SET_MAKE@
 
+
 VPATH = @srcdir@
 am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
 am__make_running_with_option = \
@@ -78,11 +79,13 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
+libexec_PROGRAMS = nm-dhcp-helper$(EXEEXT)
 subdir = src/dhcp-manager
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
+	$(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/gettext.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
@@ -100,30 +103,17 @@ mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
-LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__installdirs = "$(DESTDIR)$(libexecdir)" \
+	"$(DESTDIR)$(dbusservicedir)"
+PROGRAMS = $(libexec_PROGRAMS)
+am_nm_dhcp_helper_OBJECTS = nm_dhcp_helper-nm-dhcp-helper.$(OBJEXT)
+nm_dhcp_helper_OBJECTS = $(am_nm_dhcp_helper_OBJECTS)
 am__DEPENDENCIES_1 =
-libdhcp_dhclient_la_DEPENDENCIES =  \
-	$(top_builddir)/src/logging/libnm-logging.la \
-	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
-	$(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1) \
-	$(am__DEPENDENCIES_1)
-am_libdhcp_dhclient_la_OBJECTS =  \
-	libdhcp_dhclient_la-nm-dhcp-dhclient-utils.lo \
-	libdhcp_dhclient_la-nm-dhcp-dhclient.lo
-libdhcp_dhclient_la_OBJECTS = $(am_libdhcp_dhclient_la_OBJECTS)
+nm_dhcp_helper_DEPENDENCIES = $(am__DEPENDENCIES_1)
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
-libdhcp_manager_la_DEPENDENCIES =  \
-	$(top_builddir)/src/logging/libnm-logging.la \
-	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
-	$(builddir)/libdhcp-dhclient.la $(am__DEPENDENCIES_1) \
-	$(am__DEPENDENCIES_1)
-am_libdhcp_manager_la_OBJECTS = libdhcp_manager_la-nm-dhcp-client.lo \
-	libdhcp_manager_la-nm-dhcp-manager.lo \
-	libdhcp_manager_la-nm-dhcp-dhcpcd.lo
-libdhcp_manager_la_OBJECTS = $(am_libdhcp_manager_la_OBJECTS)
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -158,30 +148,41 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = $(libdhcp_dhclient_la_SOURCES) $(libdhcp_manager_la_SOURCES)
-DIST_SOURCES = $(libdhcp_dhclient_la_SOURCES) \
-	$(libdhcp_manager_la_SOURCES)
-RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
-	ctags-recursive dvi-recursive html-recursive info-recursive \
-	install-data-recursive install-dvi-recursive \
-	install-exec-recursive install-html-recursive \
-	install-info-recursive install-pdf-recursive \
-	install-ps-recursive install-recursive installcheck-recursive \
-	installdirs-recursive pdf-recursive ps-recursive \
-	tags-recursive uninstall-recursive
+SOURCES = $(nm_dhcp_helper_SOURCES)
+DIST_SOURCES = $(nm_dhcp_helper_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
-RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
-  distclean-recursive maintainer-clean-recursive
-am__recursive_targets = \
-  $(RECURSIVE_TARGETS) \
-  $(RECURSIVE_CLEAN_TARGETS) \
-  $(am__extra_recursive_targets)
-AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
-	distdir
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+DATA = $(dbusservice_DATA)
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
 # Read a list of newline-separated strings from the standard input,
 # and print each of them once, without duplicates.  Input order is
@@ -201,33 +202,7 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
-DIST_SUBDIRS = $(SUBDIRS)
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-am__relativize = \
-  dir0=`pwd`; \
-  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
-  sed_rest='s,^[^/]*/*,,'; \
-  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
-  sed_butlast='s,/*[^/]*$$,,'; \
-  while test -n "$$dir1"; do \
-    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
-    if test "$$first" != "."; then \
-      if test "$$first" = ".."; then \
-        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
-        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
-      else \
-        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
-        if test "$$first2" = "$$first"; then \
-          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
-        else \
-          dir2="../$$dir2"; \
-        fi; \
-        dir0="$$dir0"/"$$first"; \
-      fi; \
-    fi; \
-    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
-  done; \
-  reldir="$$dir2"
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
 AMTAR = @AMTAR@
@@ -253,12 +228,15 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
+DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
 DBUS_LIBS = @DBUS_LIBS@
 DBUS_SYS_DIR = @DBUS_SYS_DIR@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DHCLIENT_PATH = @DHCLIENT_PATH@
 DHCPCD_PATH = @DHCPCD_PATH@
+DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@
 DLLTOOL = @DLLTOOL@
 DNSMASQ_PATH = @DNSMASQ_PATH@
 DSYMUTIL = @DSYMUTIL@
@@ -283,7 +261,6 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
-GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -328,12 +305,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNDP_CFLAGS = @LIBNDP_CFLAGS@
+LIBNDP_LIBS = @LIBNDP_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
 LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTEAMDCTL_CFLAGS = @LIBTEAMDCTL_CFLAGS@
+LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -350,6 +331,8 @@ MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
+NEWT_CFLAGS = @NEWT_CFLAGS@
+NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
@@ -377,11 +360,16 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
 POLKIT_CFLAGS = @POLKIT_CFLAGS@
 POLKIT_LIBS = @POLKIT_LIBS@
 POSUB = @POSUB@
+PPPD_PATH = @PPPD_PATH@
 PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
+PPPOE_PATH = @PPPOE_PATH@
 QT_CFLAGS = @QT_CFLAGS@
 QT_LIBS = @QT_LIBS@
 RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
 SED = @SED@
+SELINUX_CFLAGS = @SELINUX_CFLAGS@
+SELINUX_LIBS = @SELINUX_LIBS@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
@@ -396,6 +384,7 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VALGRIND_RULES = @VALGRIND_RULES@
 VAPIGEN = @VAPIGEN@
 VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
 VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
@@ -458,6 +447,7 @@ psdir = @psdir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
+subdirs = @subdirs@
 sysconfdir = @sysconfdir@
 systemdsystemunitdir = @systemdsystemunitdir@
 target_alias = @target_alias@
@@ -468,76 +458,22 @@ with_dhclient = @with_dhclient@
 with_dhcpcd = @with_dhcpcd@
 with_netconfig = @with_netconfig@
 with_resolvconf = @with_resolvconf@
-SUBDIRS = . tests
-AM_CPPFLAGS = \
-	-I${top_srcdir} \
-	-I${top_builddir}/include \
-	-I${top_srcdir}/include \
-	-I${top_builddir}/src/generated \
-	-I${top_srcdir}/src/generated \
-	-I${top_srcdir}/src/logging \
-	-I${top_srcdir}/src/posix-signals \
-	-I${top_builddir}/libnm-util \
-	-I${top_srcdir}/libnm-util \
-	-I${top_srcdir}/src \
-	-DRUNDIR=\"$(rundir)\"
-
-noinst_LTLIBRARIES = libdhcp-manager.la libdhcp-dhclient.la
-
-################## dhclient ##################
-libdhcp_dhclient_la_SOURCES = \
-	nm-dhcp-dhclient-utils.h \
-	nm-dhcp-dhclient-utils.c \
-	nm-dhcp-dhclient.h \
-	nm-dhcp-dhclient.c
-
-libdhcp_dhclient_la_CPPFLAGS = \
+with_valgrind = @with_valgrind@
+nm_dhcp_helper_SOURCES = nm-dhcp-helper.c
+nm_dhcp_helper_CPPFLAGS = \
 	$(DBUS_CFLAGS) \
-	$(GLIB_CFLAGS) \
-	$(AM_CPPFLAGS) \
-	-DSYSCONFDIR=\"$(sysconfdir)\" \
-	-DLIBEXECDIR=\"$(libexecdir)\" \
-	-DLOCALSTATEDIR=\"$(localstatedir)\" \
-	-DDHCLIENT_PATH=\"$(DHCLIENT_PATH)\" \
-	-DNMSTATEDIR=\"$(nmstatedir)\" \
-	-DNMCONFDIR=\"$(nmconfdir)\"
-
-libdhcp_dhclient_la_LIBADD = \
-	$(top_builddir)/src/logging/libnm-logging.la \
-	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
-	$(top_builddir)/libnm-util/libnm-util.la \
-	$(DBUS_LIBS) \
-	$(GLIB_LIBS)
-
-
-################## main lib ##################
-libdhcp_manager_la_SOURCES = \
-	nm-dhcp-client.c \
-	nm-dhcp-client.h \
-	nm-dhcp-manager.c \
-	nm-dhcp-manager.h \
-	nm-dhcp-dhcpcd.h \
-	nm-dhcp-dhcpcd.c
-
-libdhcp_manager_la_CPPFLAGS = \
-	$(DBUS_CFLAGS) \
-	$(GLIB_CFLAGS) \
-	$(AM_CPPFLAGS) \
-	-DSYSCONFDIR=\"$(sysconfdir)\" \
-	-DLIBEXECDIR=\"$(libexecdir)\" \
-	-DLOCALSTATEDIR=\"$(localstatedir)\" \
-	-DDHCLIENT_PATH=\"$(DHCLIENT_PATH)\" \
-	-DDHCPCD_PATH=\"$(DHCPCD_PATH)\" \
-	-DNMSTATEDIR=\"$(nmstatedir)\"
-
-libdhcp_manager_la_LIBADD = \
-	$(top_builddir)/src/logging/libnm-logging.la \
-	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
-	$(builddir)/libdhcp-dhclient.la \
-	$(DBUS_LIBS) \
-	$(GLIB_LIBS)
-
-all: all-recursive
+	-DG_LOG_DOMAIN=\""nm-dhcp-helper"\" \
+	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+	-DNMRUNDIR=\"$(nmrundir)\"
+
+nm_dhcp_helper_LDADD = $(DBUS_LIBS)
+
+# FIXME: remove when dbus-glib >= 0.100 is required
+dhcp_helper_conf = nm-dhcp-helper.conf
+@HAVE_DBUS_GLIB_100_FALSE@dbusservicedir = $(DBUS_SYS_DIR)
+@HAVE_DBUS_GLIB_100_FALSE@dbusservice_DATA = $(dhcp_helper_conf)
+EXTRA_DIST = $(dhcp_helper_conf)
+all: all-am
 
 .SUFFIXES:
 .SUFFIXES: .c .lo .o .obj
@@ -571,23 +507,59 @@ $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
 $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 $(am__aclocal_m4_deps):
-
-clean-noinstLTLIBRARIES:
-	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
-	@list='$(noinst_LTLIBRARIES)'; \
-	locs=`for p in $$list; do echo $$p; done | \
-	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
-	      sort -u`; \
-	test -z "$$locs" || { \
-	  echo rm -f $${locs}; \
-	  rm -f $${locs}; \
-	}
-
-libdhcp-dhclient.la: $(libdhcp_dhclient_la_OBJECTS) $(libdhcp_dhclient_la_DEPENDENCIES) $(EXTRA_libdhcp_dhclient_la_DEPENDENCIES) 
-	$(AM_V_CCLD)$(LINK)  $(libdhcp_dhclient_la_OBJECTS) $(libdhcp_dhclient_la_LIBADD) $(LIBS)
-
-libdhcp-manager.la: $(libdhcp_manager_la_OBJECTS) $(libdhcp_manager_la_DEPENDENCIES) $(EXTRA_libdhcp_manager_la_DEPENDENCIES) 
-	$(AM_V_CCLD)$(LINK)  $(libdhcp_manager_la_OBJECTS) $(libdhcp_manager_la_LIBADD) $(LIBS)
+install-libexecPROGRAMS: $(libexec_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	@list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \
+	fi; \
+	for p in $$list; do echo "$$p $$p"; done | \
+	sed 's/$(EXEEXT)$$//' | \
+	while read p p1; do if test -f $$p \
+	 || test -f $$p1 \
+	  ; then echo "$$p"; echo "$$p"; else :; fi; \
+	done | \
+	sed -e 'p;s,.*/,,;n;h' \
+	    -e 's|.*|.|' \
+	    -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+	sed 'N;N;N;s,\n, ,g' | \
+	$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+	  { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+	    if ($$2 == $$4) files[d] = files[d] " " $$1; \
+	    else { print "f", $$3 "/" $$4, $$1; } } \
+	  END { for (d in files) print "f", d, files[d] }' | \
+	while read type dir files; do \
+	    if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+	    test -z "$$files" || { \
+	    echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \
+	    $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \
+	    } \
+	; done
+
+uninstall-libexecPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+	files=`for p in $$list; do echo "$$p"; done | \
+	  sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+	      -e 's/$$/$(EXEEXT)/' \
+	`; \
+	test -n "$$list" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(libexecdir)" && rm -f $$files
+
+clean-libexecPROGRAMS:
+	@list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+nm-dhcp-helper$(EXEEXT): $(nm_dhcp_helper_OBJECTS) $(nm_dhcp_helper_DEPENDENCIES) $(EXTRA_nm_dhcp_helper_DEPENDENCIES) 
+	@rm -f nm-dhcp-helper$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(nm_dhcp_helper_OBJECTS) $(nm_dhcp_helper_LDADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -595,11 +567,7 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdhcp_dhclient_la-nm-dhcp-dhclient-utils.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdhcp_dhclient_la-nm-dhcp-dhclient.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdhcp_manager_la-nm-dhcp-client.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdhcp_manager_la-nm-dhcp-dhcpcd.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdhcp_manager_la-nm-dhcp-manager.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm_dhcp_helper-nm-dhcp-helper.Po@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -622,102 +590,55 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
-libdhcp_dhclient_la-nm-dhcp-dhclient-utils.lo: nm-dhcp-dhclient-utils.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdhcp_dhclient_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdhcp_dhclient_la-nm-dhcp-dhclient-utils.lo -MD -MP -MF $(DEPDIR)/libdhcp_dhclient_la-nm-dhcp-dhclient-utils.Tpo -c -o libdhcp_dhclient_la-nm-dhcp-dhclient-utils.lo `test -f 'nm-dhcp-dhclient-utils.c' || echo '$(srcdir)/'`nm-dhcp-dhclient-utils.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libdhcp_dhclient_la-nm-dhcp-dhclient-utils.Tpo $(DEPDIR)/libdhcp_dhclient_la-nm-dhcp-dhclient-utils.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-dhcp-dhclient-utils.c' object='libdhcp_dhclient_la-nm-dhcp-dhclient-utils.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdhcp_dhclient_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdhcp_dhclient_la-nm-dhcp-dhclient-utils.lo `test -f 'nm-dhcp-dhclient-utils.c' || echo '$(srcdir)/'`nm-dhcp-dhclient-utils.c
-
-libdhcp_dhclient_la-nm-dhcp-dhclient.lo: nm-dhcp-dhclient.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdhcp_dhclient_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdhcp_dhclient_la-nm-dhcp-dhclient.lo -MD -MP -MF $(DEPDIR)/libdhcp_dhclient_la-nm-dhcp-dhclient.Tpo -c -o libdhcp_dhclient_la-nm-dhcp-dhclient.lo `test -f 'nm-dhcp-dhclient.c' || echo '$(srcdir)/'`nm-dhcp-dhclient.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libdhcp_dhclient_la-nm-dhcp-dhclient.Tpo $(DEPDIR)/libdhcp_dhclient_la-nm-dhcp-dhclient.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-dhcp-dhclient.c' object='libdhcp_dhclient_la-nm-dhcp-dhclient.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdhcp_dhclient_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdhcp_dhclient_la-nm-dhcp-dhclient.lo `test -f 'nm-dhcp-dhclient.c' || echo '$(srcdir)/'`nm-dhcp-dhclient.c
-
-libdhcp_manager_la-nm-dhcp-client.lo: nm-dhcp-client.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdhcp_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdhcp_manager_la-nm-dhcp-client.lo -MD -MP -MF $(DEPDIR)/libdhcp_manager_la-nm-dhcp-client.Tpo -c -o libdhcp_manager_la-nm-dhcp-client.lo `test -f 'nm-dhcp-client.c' || echo '$(srcdir)/'`nm-dhcp-client.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libdhcp_manager_la-nm-dhcp-client.Tpo $(DEPDIR)/libdhcp_manager_la-nm-dhcp-client.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-dhcp-client.c' object='libdhcp_manager_la-nm-dhcp-client.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdhcp_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdhcp_manager_la-nm-dhcp-client.lo `test -f 'nm-dhcp-client.c' || echo '$(srcdir)/'`nm-dhcp-client.c
-
-libdhcp_manager_la-nm-dhcp-manager.lo: nm-dhcp-manager.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdhcp_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdhcp_manager_la-nm-dhcp-manager.lo -MD -MP -MF $(DEPDIR)/libdhcp_manager_la-nm-dhcp-manager.Tpo -c -o libdhcp_manager_la-nm-dhcp-manager.lo `test -f 'nm-dhcp-manager.c' || echo '$(srcdir)/'`nm-dhcp-manager.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libdhcp_manager_la-nm-dhcp-manager.Tpo $(DEPDIR)/libdhcp_manager_la-nm-dhcp-manager.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-dhcp-manager.c' object='libdhcp_manager_la-nm-dhcp-manager.lo' libtool=yes @AMDEPBACKSLASH@
+nm_dhcp_helper-nm-dhcp-helper.o: nm-dhcp-helper.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nm_dhcp_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm_dhcp_helper-nm-dhcp-helper.o -MD -MP -MF $(DEPDIR)/nm_dhcp_helper-nm-dhcp-helper.Tpo -c -o nm_dhcp_helper-nm-dhcp-helper.o `test -f 'nm-dhcp-helper.c' || echo '$(srcdir)/'`nm-dhcp-helper.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nm_dhcp_helper-nm-dhcp-helper.Tpo $(DEPDIR)/nm_dhcp_helper-nm-dhcp-helper.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-dhcp-helper.c' object='nm_dhcp_helper-nm-dhcp-helper.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdhcp_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdhcp_manager_la-nm-dhcp-manager.lo `test -f 'nm-dhcp-manager.c' || echo '$(srcdir)/'`nm-dhcp-manager.c
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nm_dhcp_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm_dhcp_helper-nm-dhcp-helper.o `test -f 'nm-dhcp-helper.c' || echo '$(srcdir)/'`nm-dhcp-helper.c
 
-libdhcp_manager_la-nm-dhcp-dhcpcd.lo: nm-dhcp-dhcpcd.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdhcp_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdhcp_manager_la-nm-dhcp-dhcpcd.lo -MD -MP -MF $(DEPDIR)/libdhcp_manager_la-nm-dhcp-dhcpcd.Tpo -c -o libdhcp_manager_la-nm-dhcp-dhcpcd.lo `test -f 'nm-dhcp-dhcpcd.c' || echo '$(srcdir)/'`nm-dhcp-dhcpcd.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libdhcp_manager_la-nm-dhcp-dhcpcd.Tpo $(DEPDIR)/libdhcp_manager_la-nm-dhcp-dhcpcd.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-dhcp-dhcpcd.c' object='libdhcp_manager_la-nm-dhcp-dhcpcd.lo' libtool=yes @AMDEPBACKSLASH@
+nm_dhcp_helper-nm-dhcp-helper.obj: nm-dhcp-helper.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nm_dhcp_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm_dhcp_helper-nm-dhcp-helper.obj -MD -MP -MF $(DEPDIR)/nm_dhcp_helper-nm-dhcp-helper.Tpo -c -o nm_dhcp_helper-nm-dhcp-helper.obj `if test -f 'nm-dhcp-helper.c'; then $(CYGPATH_W) 'nm-dhcp-helper.c'; else $(CYGPATH_W) '$(srcdir)/nm-dhcp-helper.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nm_dhcp_helper-nm-dhcp-helper.Tpo $(DEPDIR)/nm_dhcp_helper-nm-dhcp-helper.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-dhcp-helper.c' object='nm_dhcp_helper-nm-dhcp-helper.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdhcp_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdhcp_manager_la-nm-dhcp-dhcpcd.lo `test -f 'nm-dhcp-dhcpcd.c' || echo '$(srcdir)/'`nm-dhcp-dhcpcd.c
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nm_dhcp_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm_dhcp_helper-nm-dhcp-helper.obj `if test -f 'nm-dhcp-helper.c'; then $(CYGPATH_W) 'nm-dhcp-helper.c'; else $(CYGPATH_W) '$(srcdir)/nm-dhcp-helper.c'; fi`
 
 mostlyclean-libtool:
 	-rm -f *.lo
 
 clean-libtool:
 	-rm -rf .libs _libs
-
-# This directory's subdirectories are mostly independent; you can cd
-# into them and run 'make' without going through this Makefile.
-# To change the values of 'make' variables: instead of editing Makefiles,
-# (1) if the variable is set in 'config.status', edit 'config.status'
-#     (which will cause the Makefiles to be regenerated when you run 'make');
-# (2) otherwise, pass the desired values on the 'make' command line.
-$(am__recursive_targets):
-	@fail=; \
-	if $(am__make_keepgoing); then \
-	  failcom='fail=yes'; \
-	else \
-	  failcom='exit 1'; \
+install-dbusserviceDATA: $(dbusservice_DATA)
+	@$(NORMAL_INSTALL)
+	@list='$(dbusservice_DATA)'; test -n "$(dbusservicedir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(dbusservicedir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(dbusservicedir)" || exit 1; \
 	fi; \
-	dot_seen=no; \
-	target=`echo $@ | sed s/-recursive//`; \
-	case "$@" in \
-	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
-	  *) list='$(SUBDIRS)' ;; \
-	esac; \
-	for subdir in $$list; do \
-	  echo "Making $$target in $$subdir"; \
-	  if test "$$subdir" = "."; then \
-	    dot_seen=yes; \
-	    local_target="$$target-am"; \
-	  else \
-	    local_target="$$target"; \
-	  fi; \
-	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
-	  || eval $$failcom; \
-	done; \
-	if test "$$dot_seen" = "no"; then \
-	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
-	fi; test -z "$$fail"
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dbusservicedir)'"; \
+	  $(INSTALL_DATA) $$files "$(DESTDIR)$(dbusservicedir)" || exit $$?; \
+	done
+
+uninstall-dbusserviceDATA:
+	@$(NORMAL_UNINSTALL)
+	@list='$(dbusservice_DATA)'; test -n "$(dbusservicedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(dbusservicedir)'; $(am__uninstall_files_from_dir)
 
 ID: $(am__tagged_files)
 	$(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-recursive
+tags: tags-am
 TAGS: tags
 
 tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
 	set x; \
 	here=`pwd`; \
-	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
-	  include_option=--etags-include; \
-	  empty_fix=.; \
-	else \
-	  include_option=--include; \
-	  empty_fix=; \
-	fi; \
-	list='$(SUBDIRS)'; for subdir in $$list; do \
-	  if test "$$subdir" = .; then :; else \
-	    test ! -f $$subdir/TAGS || \
-	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
-	  fi; \
-	done; \
 	$(am__define_uniq_tagged_files); \
 	shift; \
 	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
@@ -730,7 +651,7 @@ tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
 	      $$unique; \
 	  fi; \
 	fi
-ctags: ctags-recursive
+ctags: ctags-am
 
 CTAGS: ctags
 ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
@@ -743,7 +664,7 @@ GTAGS:
 	here=`$(am__cd) $(top_builddir) && pwd` \
 	  && $(am__cd) $(top_srcdir) \
 	  && gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-recursive
+cscopelist: cscopelist-am
 
 cscopelist-am: $(am__tagged_files)
 	list='$(am__tagged_files)'; \
@@ -792,45 +713,22 @@ distdir: $(DISTFILES)
 	    || exit 1; \
 	  fi; \
 	done
-	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
-	  if test "$$subdir" = .; then :; else \
-	    $(am__make_dryrun) \
-	      || test -d "$(distdir)/$$subdir" \
-	      || $(MKDIR_P) "$(distdir)/$$subdir" \
-	      || exit 1; \
-	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
-	    $(am__relativize); \
-	    new_distdir=$$reldir; \
-	    dir1=$$subdir; dir2="$(top_distdir)"; \
-	    $(am__relativize); \
-	    new_top_distdir=$$reldir; \
-	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
-	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
-	    ($(am__cd) $$subdir && \
-	      $(MAKE) $(AM_MAKEFLAGS) \
-	        top_distdir="$$new_top_distdir" \
-	        distdir="$$new_distdir" \
-		am__remove_distdir=: \
-		am__skip_length_check=: \
-		am__skip_mode_fix=: \
-	        distdir) \
-	      || exit 1; \
-	  fi; \
-	done
 check-am: all-am
-check: check-recursive
-all-am: Makefile $(LTLIBRARIES)
-installdirs: installdirs-recursive
-installdirs-am:
-install: install-recursive
-install-exec: install-exec-recursive
-install-data: install-data-recursive
-uninstall: uninstall-recursive
+check: check-am
+all-am: Makefile $(PROGRAMS) $(DATA)
+installdirs:
+	for dir in "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(dbusservicedir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
 
 install-am: all-am
 	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
 
-installcheck: installcheck-recursive
+installcheck: installcheck-am
 install-strip:
 	if test -z '$(STRIP)'; then \
 	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
@@ -852,93 +750,94 @@ distclean-generic:
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
 	@echo "it deletes files that may require special tools to rebuild."
-clean: clean-recursive
+clean: clean-am
 
-clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+clean-am: clean-generic clean-libexecPROGRAMS clean-libtool \
 	mostlyclean-am
 
-distclean: distclean-recursive
+distclean: distclean-am
 	-rm -rf ./$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-tags
 
-dvi: dvi-recursive
+dvi: dvi-am
 
 dvi-am:
 
-html: html-recursive
+html: html-am
 
 html-am:
 
-info: info-recursive
+info: info-am
 
 info-am:
 
-install-data-am:
+install-data-am: install-dbusserviceDATA
 
-install-dvi: install-dvi-recursive
+install-dvi: install-dvi-am
 
 install-dvi-am:
 
-install-exec-am:
+install-exec-am: install-libexecPROGRAMS
 
-install-html: install-html-recursive
+install-html: install-html-am
 
 install-html-am:
 
-install-info: install-info-recursive
+install-info: install-info-am
 
 install-info-am:
 
 install-man:
 
-install-pdf: install-pdf-recursive
+install-pdf: install-pdf-am
 
 install-pdf-am:
 
-install-ps: install-ps-recursive
+install-ps: install-ps-am
 
 install-ps-am:
 
 installcheck-am:
 
-maintainer-clean: maintainer-clean-recursive
+maintainer-clean: maintainer-clean-am
 	-rm -rf ./$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
-mostlyclean: mostlyclean-recursive
+mostlyclean: mostlyclean-am
 
 mostlyclean-am: mostlyclean-compile mostlyclean-generic \
 	mostlyclean-libtool
 
-pdf: pdf-recursive
+pdf: pdf-am
 
 pdf-am:
 
-ps: ps-recursive
+ps: ps-am
 
 ps-am:
 
-uninstall-am:
+uninstall-am: uninstall-dbusserviceDATA uninstall-libexecPROGRAMS
 
-.MAKE: $(am__recursive_targets) install-am install-strip
+.MAKE: install-am install-strip
 
-.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
-	check-am clean clean-generic clean-libtool \
-	clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \
-	distclean-compile distclean-generic distclean-libtool \
-	distclean-tags distdir dvi dvi-am html html-am info info-am \
-	install install-am install-data install-data-am install-dvi \
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libexecPROGRAMS clean-libtool cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dbusserviceDATA install-dvi \
 	install-dvi-am install-exec install-exec-am install-html \
-	install-html-am install-info install-info-am install-man \
-	install-pdf install-pdf-am install-ps install-ps-am \
-	install-strip installcheck installcheck-am installdirs \
-	installdirs-am maintainer-clean maintainer-clean-generic \
-	mostlyclean mostlyclean-compile mostlyclean-generic \
-	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
-	uninstall-am
+	install-html-am install-info install-info-am \
+	install-libexecPROGRAMS install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am uninstall-dbusserviceDATA \
+	uninstall-libexecPROGRAMS
 
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c
index 980fcab8..03c11c74 100644
--- a/src/dhcp-manager/nm-dhcp-client.c
+++ b/src/dhcp-manager/nm-dhcp-client.c
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <uuid/uuid.h>
 
+#include "NetworkManagerUtils.h"
 #include "nm-utils.h"
 #include "nm-logging.h"
 #include "nm-dbus-glib-types.h"
@@ -38,6 +39,7 @@ typedef struct {
 	GByteArray * hwaddr;
 	gboolean     ipv6;
 	char *       uuid;
+	guint        priority;
 	guint32      timeout;
 	GByteArray * duid;
 
@@ -57,9 +59,9 @@ typedef struct {
 G_DEFINE_TYPE_EXTENDED (NMDHCPClient, nm_dhcp_client, G_TYPE_OBJECT, G_TYPE_FLAG_ABSTRACT, {})
 
 enum {
-	STATE_CHANGED,
-	TIMEOUT,
-	REMOVE,
+	SIGNAL_STATE_CHANGED,
+	SIGNAL_TIMEOUT,
+	SIGNAL_REMOVE,
 	LAST_SIGNAL
 };
 
@@ -71,6 +73,7 @@ enum {
 	PROP_HWADDR,
 	PROP_IPV6,
 	PROP_UUID,
+	PROP_PRIORITY,
 	PROP_TIMEOUT,
 	LAST_PROP
 };
@@ -80,7 +83,6 @@ enum {
 GPid
 nm_dhcp_client_get_pid (NMDHCPClient *self)
 {
-	g_return_val_if_fail (self != NULL, -1);
 	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), -1);
 
 	return NM_DHCP_CLIENT_GET_PRIVATE (self)->pid;
@@ -89,7 +91,6 @@ nm_dhcp_client_get_pid (NMDHCPClient *self)
 const char *
 nm_dhcp_client_get_iface (NMDHCPClient *self)
 {
-	g_return_val_if_fail (self != NULL, NULL);
 	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
 
 	return NM_DHCP_CLIENT_GET_PRIVATE (self)->iface;
@@ -98,7 +99,6 @@ nm_dhcp_client_get_iface (NMDHCPClient *self)
 gboolean
 nm_dhcp_client_get_ipv6 (NMDHCPClient *self)
 {
-	g_return_val_if_fail (self != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE);
 
 	return NM_DHCP_CLIENT_GET_PRIVATE (self)->ipv6;
@@ -107,7 +107,6 @@ nm_dhcp_client_get_ipv6 (NMDHCPClient *self)
 const char *
 nm_dhcp_client_get_uuid (NMDHCPClient *self)
 {
-	g_return_val_if_fail (self != NULL, NULL);
 	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
 
 	return NM_DHCP_CLIENT_GET_PRIVATE (self)->uuid;
@@ -138,9 +137,9 @@ watch_cleanup (NMDHCPClient *self)
 }
 
 void
-nm_dhcp_client_stop_pid (GPid pid, const char *iface, guint timeout_secs)
+nm_dhcp_client_stop_pid (GPid pid, const char *iface)
 {
-	int i = (timeout_secs ? timeout_secs : 3) * 5;  /* default 3 seconds */
+	int i = 5;  /* roughly 0.5 seconds */
 
 	g_return_if_fail (pid > 0);
 
@@ -167,7 +166,7 @@ nm_dhcp_client_stop_pid (GPid pid, const char *iface, guint timeout_secs)
 				break;
 			}
 		}
-		g_usleep (G_USEC_PER_SEC / 5);
+		g_usleep (G_USEC_PER_SEC / 10);
 	}
 
 	if (i <= 0) {
@@ -188,7 +187,6 @@ stop (NMDHCPClient *self, gboolean release, const GByteArray *duid)
 {
 	NMDHCPClientPrivate *priv;
 
-	g_return_if_fail (self != NULL);
 	g_return_if_fail (NM_IS_DHCP_CLIENT (self));
 
 	priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
@@ -197,7 +195,7 @@ stop (NMDHCPClient *self, gboolean release, const GByteArray *duid)
 	/* Clean up the watch handler since we're explicitly killing the daemon */
 	watch_cleanup (self);
 
-	nm_dhcp_client_stop_pid (priv->pid, priv->iface, 0);
+	nm_dhcp_client_stop_pid (priv->pid, priv->iface);
 
 	priv->info_only = FALSE;
 }
@@ -213,7 +211,7 @@ daemon_timeout (gpointer user_data)
 	} else {
 		nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 request timed out.", priv->iface);
 	}
-	g_signal_emit (G_OBJECT (self), signals[TIMEOUT], 0);
+	g_signal_emit (G_OBJECT (self), signals[SIGNAL_TIMEOUT], 0);
 	return FALSE;
 }
 
@@ -223,7 +221,7 @@ signal_remove (gpointer user_data)
 	NMDHCPClient *self = NM_DHCP_CLIENT (user_data);
 
 	NM_DHCP_CLIENT_GET_PRIVATE (self)->remove_id = 0;
-	g_signal_emit (G_OBJECT (self), signals[REMOVE], 0);
+	g_signal_emit (G_OBJECT (self), signals[SIGNAL_REMOVE], 0);
 	return FALSE;
 }
 
@@ -238,12 +236,12 @@ dhcp_client_set_state (NMDHCPClient *self,
 	priv->state = state;
 
 	if (emit_state)
-		g_signal_emit (G_OBJECT (self), signals[STATE_CHANGED], 0, priv->state);
+		g_signal_emit (G_OBJECT (self), signals[SIGNAL_STATE_CHANGED], 0, priv->state);
 
 	if (state == DHC_END || state == DHC_ABEND) {
 		/* Start the remove signal timer */
 		if (remove_now) {
-			g_signal_emit (G_OBJECT (self), signals[REMOVE], 0);
+			g_signal_emit (G_OBJECT (self), signals[SIGNAL_REMOVE], 0);
 		} else {
 			if (!priv->remove_id)
 				priv->remove_id = g_timeout_add_seconds (5, signal_remove, self);
@@ -299,13 +297,12 @@ start_monitor (NMDHCPClient *self)
 
 gboolean
 nm_dhcp_client_start_ip4 (NMDHCPClient *self,
-                          NMSettingIP4Config *s_ip4,
-                          guint8 *dhcp_anycast_addr,
+                          const char *dhcp_client_id,
+                          GByteArray *dhcp_anycast_addr,
                           const char *hostname)
 {
 	NMDHCPClientPrivate *priv;
 
-	g_return_val_if_fail (self != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE);
 
 	priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
@@ -316,7 +313,7 @@ nm_dhcp_client_start_ip4 (NMDHCPClient *self,
 	nm_log_info (LOGD_DHCP, "Activation (%s) Beginning DHCPv4 transaction (timeout in %d seconds)",
 	             priv->iface, priv->timeout);
 
-	priv->pid = NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, s_ip4, dhcp_anycast_addr, hostname);
+	priv->pid = NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_client_id, dhcp_anycast_addr, hostname);
 	if (priv->pid)
 		start_monitor (self);
 
@@ -334,7 +331,7 @@ machine_id_parse (const char *in, uuid_t uu)
 	g_return_val_if_fail (in != NULL, FALSE);
 	g_return_val_if_fail (strlen (in) == 32, FALSE);
 
-	for (i = 0; i < 32; i++, cp++) {
+	for (i = 0; i < 32; i++) {
 		if (!g_ascii_isxdigit (in[i]))
 			return FALSE;
 	}
@@ -437,7 +434,7 @@ get_duid (NMDHCPClient *self)
 		duid = generate_duid_from_machine_id ();
 		g_assert (duid);
 
-		if (nm_logging_level_enabled (LOGL_DEBUG)) {
+		if (nm_logging_enabled (LOGL_DEBUG, LOGD_DHCP6)) {
 			escaped = escape_duid (duid);
 			nm_log_dbg (LOGD_DHCP6, "Generated DUID %s", escaped);
 			g_free (escaped);
@@ -454,15 +451,13 @@ get_duid (NMDHCPClient *self)
 
 gboolean
 nm_dhcp_client_start_ip6 (NMDHCPClient *self,
-                          NMSettingIP6Config *s_ip6,
-                          guint8 *dhcp_anycast_addr,
+                          GByteArray *dhcp_anycast_addr,
                           const char *hostname,
                           gboolean info_only)
 {
 	NMDHCPClientPrivate *priv;
 	char *escaped;
 
-	g_return_val_if_fail (self != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE);
 
 	priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
@@ -476,7 +471,7 @@ nm_dhcp_client_start_ip6 (NMDHCPClient *self,
 	if (!priv->duid)
 		priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self);
 
-	if (nm_logging_level_enabled (LOGL_DEBUG)) {
+	if (nm_logging_enabled (LOGL_DEBUG, LOGD_DHCP)) {
 		escaped = escape_duid (priv->duid);
 		nm_log_dbg (LOGD_DHCP, "(%s): DHCPv6 DUID is '%s'", priv->iface, escaped);
 		g_free (escaped);
@@ -488,7 +483,6 @@ nm_dhcp_client_start_ip6 (NMDHCPClient *self,
 	             priv->iface, priv->timeout);
 
 	priv->pid = NM_DHCP_CLIENT_GET_CLASS (self)->ip6_start (self,
-	                                                        s_ip6,
 	                                                        dhcp_anycast_addr,
 	                                                        hostname,
 	                                                        info_only,
@@ -524,11 +518,13 @@ nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name)
 				exe = proc_contents;
 
 			if (!strcmp (exe, binary_name))
-				nm_dhcp_client_stop_pid ((GPid) tmp, NULL, 0);
+				nm_dhcp_client_stop_pid ((GPid) tmp, NULL);
 		}
 	}
 
-	remove (pid_file);
+	if (remove (pid_file) == -1)
+		nm_log_dbg (LOGD_DHCP, "Could not remove dhcp pid file \"%s\": %d (%s)", pid_file, errno, g_strerror (errno));
+
 	g_free (proc_path);
 	g_free (pid_contents);
 	g_free (proc_contents);
@@ -539,7 +535,6 @@ nm_dhcp_client_stop (NMDHCPClient *self, gboolean release)
 {
 	NMDHCPClientPrivate *priv;
 
-	g_return_if_fail (self != NULL);
 	g_return_if_fail (NM_IS_DHCP_CLIENT (self));
 
 	priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
@@ -582,63 +577,54 @@ state_is_bound (guint32 state)
 	return FALSE;
 }
 
-typedef struct {
-	NMDHCPState state;
-	const char *name;
-} DhcState;
-
-#define STATE_TABLE_SIZE (sizeof (state_table) / sizeof (state_table[0]))
-
-static DhcState state_table[] = {
-	{ DHC_NBI,     "nbi" },
-	{ DHC_PREINIT, "preinit" },
-	{ DHC_PREINIT6,"preinit6" },
-	{ DHC_BOUND4,  "bound" },
-	{ DHC_BOUND6,  "bound6" },
-	{ DHC_IPV4LL,  "ipv4ll" },
-	{ DHC_RENEW4,  "renew" },
-	{ DHC_RENEW6,  "renew6" },
-	{ DHC_REBOOT,  "reboot" },
-	{ DHC_REBIND4, "rebind" },
-	{ DHC_REBIND6, "rebind6" },
-	{ DHC_STOP,    "stop" },
-	{ DHC_STOP6,   "stop6" },
-	{ DHC_MEDIUM,  "medium" },
-	{ DHC_TIMEOUT, "timeout" },
-	{ DHC_FAIL,    "fail" },
-	{ DHC_EXPIRE,  "expire" },
-	{ DHC_EXPIRE6, "expire6" },
-	{ DHC_RELEASE, "release" },
-	{ DHC_RELEASE6,"release6" },
-	{ DHC_START,   "start" },
-	{ DHC_ABEND,   "abend" },
-	{ DHC_END,     "end" },
-	{ DHC_DEPREF6, "depref6" },
+static const char *state_table[] = {
+	[DHC_NBI]             = "nbi",
+	[DHC_PREINIT]         = "preinit",
+	[DHC_PREINIT6]        = "preinit6",
+	[DHC_BOUND4]          = "bound",
+	[DHC_BOUND6]          = "bound6",
+	[DHC_IPV4LL]          = "ipv4ll",
+	[DHC_RENEW4]          = "renew",
+	[DHC_RENEW6]          = "renew6",
+	[DHC_REBOOT]          = "reboot",
+	[DHC_REBIND4]         = "rebind",
+	[DHC_REBIND6]         = "rebind6",
+	[DHC_DEPREF6]         = "depref6",
+	[DHC_STOP]            = "stop",
+	[DHC_STOP6]           = "stop6",
+	[DHC_MEDIUM]          = "medium",
+	[DHC_TIMEOUT]         = "timeout",
+	[DHC_FAIL]            = "fail",
+	[DHC_EXPIRE]          = "expire",
+	[DHC_EXPIRE6]         = "expire6",
+	[DHC_RELEASE]         = "release",
+	[DHC_RELEASE6]        = "release6",
+	[DHC_START]           = "start",
+	[DHC_ABEND]           = "abend",
+	[DHC_END]             = "end",
 };
 
-static inline const char *
-state_to_string (guint32 state)
+static const char *
+state_to_string (NMDHCPState state)
 {
-	int i;
-
-	for (i = 0; i < STATE_TABLE_SIZE; i++) {
-		if (state == state_table[i].state)
-			return state_table[i].name;
-	}
-
+	if (state >= 0 && state < G_N_ELEMENTS (state_table))
+		return state_table[state];
 	return NULL;
 }
 
-static inline NMDHCPState
+static NMDHCPState
 string_to_state (const char *name)
 {
 	int i;
 
-	for (i = 0; i < STATE_TABLE_SIZE; i++) {
-		if (!strcasecmp (name, state_table[i].name))
-			return state_table[i].state;
-	}
+	if (name) {
+		for (i = 0; i < G_N_ELEMENTS (state_table); i++) {
+			const char *n = state_table[i];
 
+			if (n && !strcasecmp (name, n))
+				return i;
+		}
+	}
 	return 255;
 }
 
@@ -705,7 +691,6 @@ nm_dhcp_client_new_options (NMDHCPClient *self,
 	guint32 old_state;
 	guint32 new_state;
 
-	g_return_if_fail (self != NULL);
 	g_return_if_fail (NM_IS_DHCP_CLIENT (self));
 	g_return_if_fail (options != NULL);
 	g_return_if_fail (reason != NULL);
@@ -766,7 +751,6 @@ nm_dhcp_client_foreach_option (NMDHCPClient *self,
 	GHashTableIter iter;
 	gpointer iterkey, itervalue;
 
-	g_return_val_if_fail (self != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE);
 	g_return_val_if_fail (func != NULL, FALSE);
 
@@ -813,10 +797,12 @@ nm_dhcp_client_foreach_option (NMDHCPClient *self,
 /********************************************/
 
 static gboolean
-ip4_process_dhcpcd_rfc3442_routes (const char *str,
+ip4_process_dhcpcd_rfc3442_routes (NMDHCPClient *self,
+                                   const char *str,
                                    NMIP4Config *ip4_config,
                                    guint32 *gwaddr)
 {
+	NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
 	char **routes, **r;
 	gboolean have_routes = FALSE;
 
@@ -831,10 +817,9 @@ ip4_process_dhcpcd_rfc3442_routes (const char *str,
 
 	for (r = routes; *r; r += 2) {
 		char *slash;
-		NMIP4Route *route;
+		NMPlatformIP4Route route;
 		int rt_cidr = 32;
-		struct in_addr rt_addr;
-		struct in_addr rt_route;
+		guint32 rt_addr, rt_route;
 
 		slash = strchr(*r, '/');
 		if (slash) {
@@ -856,17 +841,18 @@ ip4_process_dhcpcd_rfc3442_routes (const char *str,
 		}
 
 		have_routes = TRUE;
-		if (rt_cidr == 0 && rt_addr.s_addr == 0) {
+		if (rt_cidr == 0 && rt_addr == 0) {
 			/* FIXME: how to handle multiple routers? */
-			*gwaddr = rt_route.s_addr;
+			*gwaddr = rt_route;
 		} else {
-			route = nm_ip4_route_new ();
-			nm_ip4_route_set_dest (route, (guint32) rt_addr.s_addr);
-			nm_ip4_route_set_prefix (route, rt_cidr);
-			nm_ip4_route_set_next_hop (route, (guint32) rt_route.s_addr);
-
-			nm_ip4_config_take_route (ip4_config, route);
 			nm_log_info (LOGD_DHCP4, "  classless static route %s/%d gw %s", *r, rt_cidr, *(r + 1));
+			memset (&route, 0, sizeof (route));
+			route.network = rt_addr;
+			route.plen = rt_cidr;
+			route.gateway = rt_route;
+			route.source = NM_PLATFORM_SOURCE_DHCP;
+			route.metric = priv->priority;
+			nm_ip4_config_add_route (ip4_config, &route);
 		}
 	}
 
@@ -876,14 +862,15 @@ out:
 }
 
 static const char **
-process_dhclient_rfc3442_route (const char **octets, NMIP4Route **out_route)
+process_dhclient_rfc3442_route (const char **octets, NMPlatformIP4Route *route, gboolean *success)
 {
 	const char **o = octets;
 	int addr_len = 0, i = 0;
 	long int tmp;
-	NMIP4Route *route;
 	char *next_hop;
-	struct in_addr tmp_addr;
+	guint32 tmp_addr;
+
+	*success = FALSE;
 
 	if (!*o)
 		return o; /* no prefix */
@@ -892,8 +879,8 @@ process_dhclient_rfc3442_route (const char **octets, NMIP4Route **out_route)
 	if (tmp < 0 || tmp > 32)  /* 32 == max IP4 prefix length */
 		return o;
 
-	route = nm_ip4_route_new ();
-	nm_ip4_route_set_prefix (route, (guint32) tmp);
+	memset (route, 0, sizeof (*route));
+	route->plen = tmp;
 	o++;
 
 	if (tmp > 0)
@@ -915,8 +902,8 @@ process_dhclient_rfc3442_route (const char **octets, NMIP4Route **out_route)
 			g_free (str_addr);
 			goto error;
 		}
-		tmp_addr.s_addr &= nm_utils_ip4_prefix_to_netmask ((guint32) tmp);
-		nm_ip4_route_set_dest (route, tmp_addr.s_addr);
+		tmp_addr &= nm_utils_ip4_prefix_to_netmask ((guint32) tmp);
+		route->network = tmp_addr;
 	}
 
 	/* Handle next hop */
@@ -925,25 +912,27 @@ process_dhclient_rfc3442_route (const char **octets, NMIP4Route **out_route)
 		g_free (next_hop);
 		goto error;
 	}
-	nm_ip4_route_set_next_hop (route, tmp_addr.s_addr);
+	route->gateway = tmp_addr;
 	g_free (next_hop);
 
-	*out_route = route;
+	*success = TRUE;
 	return o + 4; /* advance to past the next hop */
 
 error:
-	nm_ip4_route_unref (route);
 	return o;
 }
 
 static gboolean
-ip4_process_dhclient_rfc3442_routes (const char *str,
+ip4_process_dhclient_rfc3442_routes (NMDHCPClient *self,
+                                     const char *str,
                                      NMIP4Config *ip4_config,
                                      guint32 *gwaddr)
 {
+	NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
 	char **octets, **o;
 	gboolean have_routes = FALSE;
-	NMIP4Route *route = NULL;
+	NMPlatformIP4Route route;
+	gboolean success;
 
 	o = octets = g_strsplit_set (str, " .", 0);
 	if (g_strv_length (octets) < 5) {
@@ -952,32 +941,28 @@ ip4_process_dhclient_rfc3442_routes (const char *str,
 	}
 
 	while (*o) {
-		route = NULL;
-		o = (char **) process_dhclient_rfc3442_route ((const char **) o, &route);
-		if (!route) {
+		memset (&route, 0, sizeof (route));
+		o = (char **) process_dhclient_rfc3442_route ((const char **) o, &route, &success);
+		if (!success) {
 			nm_log_warn (LOGD_DHCP4, "ignoring invalid classless static routes");
 			break;
 		}
 
 		have_routes = TRUE;
-		if (nm_ip4_route_get_prefix (route) == 0) {
+		if (!route.plen) {
 			/* gateway passed as classless static route */
-			*gwaddr = nm_ip4_route_get_next_hop (route);
-			nm_ip4_route_unref (route);
+			*gwaddr = route.gateway;
 		} else {
-			char addr[INET_ADDRSTRLEN + 1];
-			char nh[INET_ADDRSTRLEN + 1];
-			struct in_addr tmp;
+			char addr[INET_ADDRSTRLEN];
 
 			/* normal route */
-			nm_ip4_config_take_route (ip4_config, route);
+			route.source = NM_PLATFORM_SOURCE_DHCP;
+			route.metric = priv->priority;
+			nm_ip4_config_add_route (ip4_config, &route);
 
-			tmp.s_addr = nm_ip4_route_get_dest (route);
-			inet_ntop (AF_INET, &tmp, addr, sizeof (addr));
-			tmp.s_addr = nm_ip4_route_get_next_hop (route);
-			inet_ntop (AF_INET, &tmp, nh, sizeof (nh));
 			nm_log_info (LOGD_DHCP4, "  classless static route %s/%d gw %s",
-			             addr, nm_ip4_route_get_prefix (route), nh);
+			             nm_utils_inet4_ntop (route.network, addr), route.plen,
+			             nm_utils_inet4_ntop (route.gateway, NULL));
 		}
 	}
 
@@ -987,7 +972,8 @@ out:
 }
 
 static gboolean
-ip4_process_classless_routes (GHashTable *options,
+ip4_process_classless_routes (NMDHCPClient *self,
+                              GHashTable *options,
                               NMIP4Config *ip4_config,
                               guint32 *gwaddr)
 {
@@ -1043,15 +1029,16 @@ ip4_process_classless_routes (GHashTable *options,
 
 	if (strchr (str, '/')) {
 		/* dhcpcd format */
-		return ip4_process_dhcpcd_rfc3442_routes (str, ip4_config, gwaddr);
+		return ip4_process_dhcpcd_rfc3442_routes (self, str, ip4_config, gwaddr);
 	}
 
-	return ip4_process_dhclient_rfc3442_routes (str, ip4_config, gwaddr);
+	return ip4_process_dhclient_rfc3442_routes (self, str, ip4_config, gwaddr);
 }
 
 static void
-process_classful_routes (GHashTable *options, NMIP4Config *ip4_config)
+process_classful_routes (NMDHCPClient *self, GHashTable *options, NMIP4Config *ip4_config)
 {
+	NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
 	const char *str;
 	char **searches, **s;
 
@@ -1066,9 +1053,8 @@ process_classful_routes (GHashTable *options, NMIP4Config *ip4_config)
 	}
 
 	for (s = searches; *s; s += 2) {
-		NMIP4Route *route;
-		struct in_addr rt_addr;
-		struct in_addr rt_route;
+		NMPlatformIP4Route route;
+		guint32 rt_addr, rt_route;
 
 		if (inet_pton (AF_INET, *s, &rt_addr) <= 0) {
 			nm_log_warn (LOGD_DHCP, "DHCP provided invalid static route address: '%s'", *s);
@@ -1079,15 +1065,26 @@ process_classful_routes (GHashTable *options, NMIP4Config *ip4_config)
 			continue;
 		}
 
-		// FIXME: ensure the IP addresse and route are sane
-
-		route = nm_ip4_route_new ();
-		nm_ip4_route_set_dest (route, (guint32) rt_addr.s_addr);
-		nm_ip4_route_set_prefix (route, 32); /* 255.255.255.255 */
-		nm_ip4_route_set_next_hop (route, (guint32) rt_route.s_addr);
+		// FIXME: ensure the IP address and route are sane
+
+		memset (&route, 0, sizeof (route));
+		route.network = rt_addr;
+		/* RFC 2132, updated by RFC 3442:
+		   The Static Routes option (option 33) does not provide a subnet mask
+		   for each route - it is assumed that the subnet mask is implicit in
+		   whatever network number is specified in each route entry */
+		route.plen = nm_utils_ip4_get_default_prefix (rt_addr);
+		if (rt_addr & ~nm_utils_ip4_prefix_to_netmask (route.plen)) {
+			/* RFC 943: target not "this network"; using host routing */
+			route.plen = 32;
+		}
+		route.gateway = rt_route;
+		route.source = NM_PLATFORM_SOURCE_DHCP;
+		route.metric = priv->priority;
 
-		nm_ip4_config_take_route (ip4_config, route);
-		nm_log_info (LOGD_DHCP, "  static route %s gw %s", *s, *(s + 1));
+		nm_ip4_config_add_route (ip4_config, &route);
+		nm_log_info (LOGD_DHCP, "  static route %s",
+		                        nm_platform_ip4_route_to_string (&route));
 	}
 
 out:
@@ -1145,59 +1142,47 @@ ip4_options_to_config (NMDHCPClient *self)
 {
 	NMDHCPClientPrivate *priv;
 	NMIP4Config *ip4_config = NULL;
-	struct in_addr tmp_addr;
-	NMIP4Address *addr = NULL;
+	guint32 tmp_addr;
+	NMPlatformIP4Address address;
 	char *str = NULL;
-	guint32 gwaddr = 0, prefix = 0;
+	guint32 gwaddr = 0, plen = 0;
 
-	g_return_val_if_fail (self != NULL, NULL);
 	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
 
 	priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
 	g_return_val_if_fail (priv->options != NULL, NULL);
 
 	ip4_config = nm_ip4_config_new ();
-	if (!ip4_config) {
-		nm_log_warn (LOGD_DHCP4, "(%s): couldn't allocate memory for an IP4Config!", priv->iface);
-		return NULL;
-	}
-
-	addr = nm_ip4_address_new ();
-	if (!addr) {
-		nm_log_warn (LOGD_DHCP4, "(%s): couldn't allocate memory for an IP4 Address!", priv->iface);
-		goto error;
-	}
+	memset (&address, 0, sizeof (address));
+	address.timestamp = nm_utils_get_monotonic_timestamp_s ();
 
 	str = g_hash_table_lookup (priv->options, "new_ip_address");
 	if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) {
-		nm_ip4_address_set_address (addr, tmp_addr.s_addr);
+		address.address = tmp_addr;
 		nm_log_info (LOGD_DHCP4, "  address %s", str);
 	} else
 		goto error;
 
 	str = g_hash_table_lookup (priv->options, "new_subnet_mask");
 	if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) {
-		prefix = nm_utils_ip4_netmask_to_prefix (tmp_addr.s_addr);
-		nm_log_info (LOGD_DHCP4, "  prefix %d (%s)", prefix, str);
+		plen = nm_utils_ip4_netmask_to_prefix (tmp_addr);
+		nm_log_info (LOGD_DHCP4, "  plen %d (%s)", plen, str);
 	} else {
 		/* Get default netmask for the IP according to appropriate class. */
-		prefix = nm_utils_ip4_get_default_prefix (nm_ip4_address_get_address (addr));
-		nm_log_info (LOGD_DHCP4, "  prefix %d (default)", prefix);
+		plen = nm_utils_ip4_get_default_prefix (address.address);
+		nm_log_info (LOGD_DHCP4, "  plen %d (default)", plen);
 	}
-	nm_ip4_address_set_prefix (addr, prefix);
+	address.plen = plen;
 
 	/* Routes: if the server returns classless static routes, we MUST ignore
 	 * the 'static_routes' option.
 	 */
-	if (!ip4_process_classless_routes (priv->options, ip4_config, &gwaddr))
-		process_classful_routes (priv->options, ip4_config);
+	if (!ip4_process_classless_routes (self, priv->options, ip4_config, &gwaddr))
+		process_classful_routes (self, priv->options, ip4_config);
 
 	if (gwaddr) {
-		char buf[INET_ADDRSTRLEN + 1];
-
-		inet_ntop (AF_INET, &gwaddr, buf, sizeof (buf));
-		nm_log_info (LOGD_DHCP4, "  gateway %s", buf);
-		nm_ip4_address_set_gateway (addr, gwaddr);
+		nm_log_info (LOGD_DHCP4, "  gateway %s", nm_utils_inet4_ntop (gwaddr, NULL));
+		nm_ip4_config_set_gateway (ip4_config, gwaddr);
 	} else {
 		/* If the gateway wasn't provided as a classless static route with a
 		 * subnet length of 0, try to find it using the old-style 'routers' option.
@@ -1209,8 +1194,8 @@ ip4_options_to_config (NMDHCPClient *self)
 
 			for (s = routers; *s; s++) {
 				/* FIXME: how to handle multiple routers? */
-				if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
-					nm_ip4_address_set_gateway (addr, tmp_addr.s_addr);
+				if (inet_pton (AF_INET, *s, &gwaddr) > 0) {
+					nm_ip4_config_set_gateway (ip4_config, gwaddr);
 					nm_log_info (LOGD_DHCP4, "  gateway %s", *s);
 					break;
 				} else
@@ -1220,8 +1205,51 @@ ip4_options_to_config (NMDHCPClient *self)
 		}
 	}
 
-	nm_ip4_config_take_address (ip4_config, addr);
-	addr = NULL;
+	/*
+	 * RFC 2132, section 9.7
+	 *   DHCP clients use the contents of the 'server identifier' field
+	 *   as the destination address for any DHCP messages unicast to
+	 *   the DHCP server.
+	 *
+	 * Some ISP's provide leases from central servers that are on
+	 * different subnets that the address offered.  If the host
+	 * does not configure the interface as the default route, the
+	 * dhcp server may not be reachable via unicast, and a host
+	 * specific route is needed.
+	 **/
+	str = g_hash_table_lookup (priv->options, "new_dhcp_server_identifier");
+	if (str) {
+		if (inet_pton (AF_INET, str, &tmp_addr) > 0) {
+			NMPlatformIP4Route route;
+			guint32 mask = nm_utils_ip4_prefix_to_netmask (address.plen);
+
+			nm_log_info (LOGD_DHCP4, "  server identifier %s", str);
+			if ((tmp_addr & mask) != (address.address & mask)) {
+				/* DHCP server not on assigned subnet, route needed */
+				memset (&route, 0, sizeof (route));
+				route.network = tmp_addr;
+				route.plen = 32;
+				/* this will be a device route if gwaddr is 0 */
+				route.gateway = gwaddr;
+				route.source = NM_PLATFORM_SOURCE_DHCP;
+				route.metric = priv->priority;
+				nm_ip4_config_add_route (ip4_config, &route);
+				nm_log_dbg (LOGD_IP, "adding route for server identifier: %s",
+				                      nm_platform_ip4_route_to_string (&route));
+			}
+		}
+		else
+			nm_log_warn (LOGD_DHCP4, "ignoring invalid server identifier '%s'", str);
+	}
+
+	str = g_hash_table_lookup (priv->options, "new_dhcp_lease_time");
+	if (str) {
+		address.lifetime = address.preferred = strtoul (str, NULL, 10);
+		nm_log_info (LOGD_DHCP4, "  lease time %d", address.lifetime);
+	}
+
+	address.source = NM_PLATFORM_SOURCE_DHCP;
+	nm_ip4_config_add_address (ip4_config, &address);
 
 	str = g_hash_table_lookup (priv->options, "new_host_name");
 	if (str)
@@ -1234,7 +1262,7 @@ ip4_options_to_config (NMDHCPClient *self)
 
 		for (s = searches; *s; s++) {
 			if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
-				nm_ip4_config_add_nameserver (ip4_config, tmp_addr.s_addr);
+				nm_ip4_config_add_nameserver (ip4_config, tmp_addr);
 				nm_log_info (LOGD_DHCP4, "  nameserver '%s'", *s);
 			} else
 				nm_log_warn (LOGD_DHCP4, "ignoring invalid nameserver '%s'", *s);
@@ -1265,7 +1293,7 @@ ip4_options_to_config (NMDHCPClient *self)
 
 		for (s = searches; *s; s++) {
 			if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
-				nm_ip4_config_add_wins (ip4_config, tmp_addr.s_addr);
+				nm_ip4_config_add_wins (ip4_config, tmp_addr);
 				nm_log_info (LOGD_DHCP4, "  wins '%s'", *s);
 			} else
 				nm_log_warn (LOGD_DHCP4, "ignoring invalid WINS server '%s'", *s);
@@ -1299,7 +1327,7 @@ ip4_options_to_config (NMDHCPClient *self)
 
 		for (s = searches; *s; s++) {
 			if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
-				nm_ip4_config_add_nis_server (ip4_config, tmp_addr.s_addr);
+				nm_ip4_config_add_nis_server (ip4_config, tmp_addr);
 				nm_log_info (LOGD_DHCP4, "  nis '%s'", *s);
 			} else
 				nm_log_warn (LOGD_DHCP4, "ignoring invalid NIS server '%s'", *s);
@@ -1310,8 +1338,6 @@ ip4_options_to_config (NMDHCPClient *self)
 	return ip4_config;
 
 error:
-	if (addr)
-		nm_ip4_address_unref (addr);
 	g_object_unref (ip4_config);
 	return NULL;
 }
@@ -1321,7 +1347,6 @@ nm_dhcp_client_get_ip4_config (NMDHCPClient *self, gboolean test)
 {
 	NMDHCPClientPrivate *priv;
 
-	g_return_val_if_fail (self != NULL, NULL);
 	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
 
 	priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
@@ -1354,14 +1379,17 @@ ip6_options_to_config (NMDHCPClient *self)
 	NMDHCPClientPrivate *priv;
 	NMIP6Config *ip6_config = NULL;
 	struct in6_addr tmp_addr;
-	NMIP6Address *addr = NULL;
+	NMPlatformIP6Address address;
 	char *str = NULL;
 	GHashTableIter iter;
 	gpointer key, value;
 
-	g_return_val_if_fail (self != NULL, NULL);
 	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
 
+	memset (&address, 0, sizeof (address));
+	address.plen = 128;
+	address.timestamp = nm_utils_get_monotonic_timestamp_s ();
+
 	priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
 	g_return_val_if_fail (priv->options != NULL, NULL);
 
@@ -1372,9 +1400,17 @@ ip6_options_to_config (NMDHCPClient *self)
 	}
 
 	ip6_config = nm_ip6_config_new ();
-	if (!ip6_config) {
-		nm_log_warn (LOGD_DHCP6, "(%s): couldn't allocate memory for an IP6Config!", priv->iface);
-		return NULL;
+
+	str = g_hash_table_lookup (priv->options, "new_max_life");
+	if (str) {
+		address.lifetime = strtoul (str, NULL, 10);
+		nm_log_info (LOGD_DHCP6, "  valid_lft %d", address.lifetime);
+	}
+
+	str = g_hash_table_lookup (priv->options, "new_preferred_life");
+	if (str) {
+		address.preferred = strtoul (str, NULL, 10);
+		nm_log_info (LOGD_DHCP6, "  preferred_lft %d", address.preferred);
 	}
 
 	str = g_hash_table_lookup (priv->options, "new_ip6_address");
@@ -1385,14 +1421,10 @@ ip6_options_to_config (NMDHCPClient *self)
 			goto error;
 		}
 
-		addr = nm_ip6_address_new ();
-		g_assert (addr);
-		nm_ip6_address_set_address (addr, &tmp_addr);
-		/* DHCPv6 IA_NA assignments are single address only */
-		nm_ip6_address_set_prefix (addr, 128);
-		nm_log_info (LOGD_DHCP6, "  address %s/128", str);
-
-		nm_ip6_config_take_address (ip6_config, addr);
+		address.address = tmp_addr;
+		address.source = NM_PLATFORM_SOURCE_DHCP;
+		nm_ip6_config_add_address (ip6_config, &address);
+		nm_log_info (LOGD_DHCP6, "  address %s", str);
 	} else if (priv->info_only == FALSE) {
 		/* No address in Managed mode is a hard error */
 		goto error;
@@ -1433,7 +1465,6 @@ nm_dhcp_client_get_ip6_config (NMDHCPClient *self, gboolean test)
 {
 	NMDHCPClientPrivate *priv;
 
-	g_return_val_if_fail (self != NULL, NULL);
 	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
 
 	priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
@@ -1481,6 +1512,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_UUID:
 		g_value_set_string (value, priv->uuid);
 		break;
+	case PROP_PRIORITY:
+		g_value_set_uint (value, priv->priority);
+		break;
 	case PROP_TIMEOUT:
 		g_value_set_uint (value, priv->timeout);
 		break;
@@ -1513,6 +1547,10 @@ set_property (GObject *object, guint prop_id,
 		/* construct-only */
 		priv->uuid = g_value_dup_string (value);
 		break;
+	case PROP_PRIORITY:
+		/* construct-only */
+		priv->priority = g_value_get_uint (value);
+		break;
 	case PROP_TIMEOUT:
 		priv->timeout = g_value_get_uint (value);
 		break;
@@ -1605,6 +1643,14 @@ nm_dhcp_client_class_init (NMDHCPClientClass *client_class)
 		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property
+		(object_class, PROP_PRIORITY,
+		 g_param_spec_uint (NM_DHCP_CLIENT_PRIORITY,
+		                    "priority",
+		                    "Priority",
+		                    0, G_MAXUINT, 0,
+		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property
 		(object_class, PROP_TIMEOUT,
 		 g_param_spec_uint (NM_DHCP_CLIENT_TIMEOUT,
 		                    "timeout",
@@ -1613,8 +1659,8 @@ nm_dhcp_client_class_init (NMDHCPClientClass *client_class)
 		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	/* signals */
-	signals[STATE_CHANGED] =
-		g_signal_new ("state-changed",
+	signals[SIGNAL_STATE_CHANGED] =
+		g_signal_new (NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
 					  G_OBJECT_CLASS_TYPE (object_class),
 					  G_SIGNAL_RUN_FIRST,
 					  G_STRUCT_OFFSET (NMDHCPClientClass, state_changed),
@@ -1622,8 +1668,8 @@ nm_dhcp_client_class_init (NMDHCPClientClass *client_class)
 					  g_cclosure_marshal_VOID__UINT,
 					  G_TYPE_NONE, 1, G_TYPE_UINT);
 
-	signals[TIMEOUT] =
-		g_signal_new ("timeout",
+	signals[SIGNAL_TIMEOUT] =
+		g_signal_new (NM_DHCP_CLIENT_SIGNAL_TIMEOUT,
 					  G_OBJECT_CLASS_TYPE (object_class),
 					  G_SIGNAL_RUN_FIRST,
 					  G_STRUCT_OFFSET (NMDHCPClientClass, timeout),
@@ -1631,8 +1677,8 @@ nm_dhcp_client_class_init (NMDHCPClientClass *client_class)
 					  g_cclosure_marshal_VOID__VOID,
 					  G_TYPE_NONE, 0);
 
-	signals[REMOVE] =
-		g_signal_new ("remove",
+	signals[SIGNAL_REMOVE] =
+		g_signal_new (NM_DHCP_CLIENT_SIGNAL_REMOVE,
 					  G_OBJECT_CLASS_TYPE (object_class),
 					  G_SIGNAL_RUN_FIRST,
 					  G_STRUCT_OFFSET (NMDHCPClientClass, remove),
diff --git a/src/dhcp-manager/nm-dhcp-client.h b/src/dhcp-manager/nm-dhcp-client.h
index 930ec1a5..ad18926a 100644
--- a/src/dhcp-manager/nm-dhcp-client.h
+++ b/src/dhcp-manager/nm-dhcp-client.h
@@ -38,8 +38,13 @@
 #define NM_DHCP_CLIENT_HWADDR    "hwaddr"
 #define NM_DHCP_CLIENT_IPV6      "ipv6"
 #define NM_DHCP_CLIENT_UUID      "uuid"
+#define NM_DHCP_CLIENT_PRIORITY  "priority"
 #define NM_DHCP_CLIENT_TIMEOUT   "timeout"
 
+#define NM_DHCP_CLIENT_SIGNAL_TIMEOUT       "timeout"
+#define NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED "state-changed"
+#define NM_DHCP_CLIENT_SIGNAL_REMOVE        "remove"
+
 typedef enum {
 	DHC_NBI = 0,     /* no broadcast interfaces found */
 	DHC_PREINIT,     /* configuration started */
@@ -78,13 +83,12 @@ typedef struct {
 	/* Methods */
 
 	GPid (*ip4_start)     (NMDHCPClient *self,
-	                       NMSettingIP4Config *s_ip4,
-	                       guint8 *anycast_addr,
+	                       const char *dhcp_client_id,
+	                       GByteArray *anycast_addr,
 	                       const char *hostname);
 
 	GPid (*ip6_start)     (NMDHCPClient *self,
-	                       NMSettingIP6Config *s_ip6,
-	                       guint8 *anycast_addr,
+	                       GByteArray *anycast_addr,
 	                       const char *hostname,
 	                       gboolean info_only,
 	                       const GByteArray *duid);
@@ -121,13 +125,12 @@ gboolean nm_dhcp_client_get_ipv6 (NMDHCPClient *self);
 const char *nm_dhcp_client_get_uuid (NMDHCPClient *self);
 
 gboolean nm_dhcp_client_start_ip4 (NMDHCPClient *self,
-                                   NMSettingIP4Config *s_ip4,
-                                   guint8 *dhcp_anycast_addr,
+                                   const char *dhcp_client_id,
+                                   GByteArray *dhcp_anycast_addr,
                                    const char *hostname);
 
 gboolean nm_dhcp_client_start_ip6 (NMDHCPClient *self,
-                                   NMSettingIP6Config *s_ip6,
-                                   guint8 *dhcp_anycast_addr,
+                                   GByteArray *dhcp_anycast_addr,
                                    const char *hostname,
                                    gboolean info_only);
 
@@ -148,7 +151,7 @@ NMIP6Config *nm_dhcp_client_get_ip6_config   (NMDHCPClient *self, gboolean test)
 /* Backend helpers */
 void nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name);
 
-void nm_dhcp_client_stop_pid (GPid pid, const char *iface, guint timeout_secs);
+void nm_dhcp_client_stop_pid (GPid pid, const char *iface);
 
 #endif /* NM_DHCP_CLIENT_H */
 
diff --git a/src/dhcp-manager/nm-dhcp-dhclient-utils.c b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
index db4bf7e8..8527e6c0 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient-utils.c
+++ b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
@@ -25,6 +25,9 @@
 #include <ctype.h>
 
 #include "nm-dhcp-dhclient-utils.h"
+#include "nm-ip4-config.h"
+#include "nm-utils.h"
+#include "NetworkManagerUtils.h"
 
 #define CLIENTID_TAG            "send dhcp-client-identifier"
 #define CLIENTID_FORMAT         CLIENTID_TAG " \"%s\"; # added by NetworkManager"
@@ -68,33 +71,32 @@ add_hostname (GString *str, const char *format, const char *hostname)
 }
 
 static void
-add_ip4_config (GString *str, NMSettingIP4Config *s_ip4, const char *hostname)
+add_ip4_config (GString *str, const char *dhcp_client_id, const char *hostname)
 {
-	if (s_ip4) {
-		const char *tmp;
-
-		tmp = nm_setting_ip4_config_get_dhcp_client_id (s_ip4);
-		if (tmp) {
-			gboolean is_octets = TRUE;
-			const char *p = tmp;
-
-			while (*p) {
-				if (!g_ascii_isxdigit (*p) && (*p != ':')) {
-					is_octets = FALSE;
-					break;
-				}
-				p++;
+	if (dhcp_client_id) {
+		gboolean is_octets = TRUE;
+		int i = 0;
+
+		while (dhcp_client_id[i]) {
+			if ((i % 3) != 2 && !g_ascii_isxdigit (dhcp_client_id[i])) {
+				is_octets = FALSE;
+				break;
 			}
-
-			/* If the client ID is just hex digits and : then don't use quotes,
-			 * because dhclient expects either a quoted ASCII string, or a byte
-			 * array formated as hex octets separated by :
-			 */
-			if (is_octets)
-				g_string_append_printf (str, CLIENTID_FORMAT_OCTETS "\n", tmp);
-			else
-				g_string_append_printf (str, CLIENTID_FORMAT "\n", tmp);
+			if ((i % 3) == 2 && dhcp_client_id[i] != ':') {
+				is_octets = FALSE;
+				break;
+			}
+			i++;
 		}
+
+		/* If the client ID is just hex digits and : then don't use quotes,
+		 * because dhclient expects either a quoted ASCII string, or a byte
+		 * array formated as hex octets separated by :
+		 */
+		if (is_octets)
+			g_string_append_printf (str, CLIENTID_FORMAT_OCTETS "\n", dhcp_client_id);
+		else
+			g_string_append_printf (str, CLIENTID_FORMAT "\n", dhcp_client_id);
 	}
 
 	add_hostname (str, HOSTNAME4_FORMAT "\n", hostname);
@@ -113,7 +115,7 @@ add_ip4_config (GString *str, NMSettingIP4Config *s_ip4, const char *hostname)
 }
 
 static void
-add_ip6_config (GString *str, NMSettingIP6Config *s_ip6, const char *hostname)
+add_ip6_config (GString *str, const char *hostname)
 {
 	add_hostname (str, HOSTNAME6_FORMAT "\n", hostname);
 	g_string_append (str,
@@ -125,9 +127,8 @@ add_ip6_config (GString *str, NMSettingIP6Config *s_ip6, const char *hostname)
 char *
 nm_dhcp_dhclient_create_config (const char *interface,
                                 gboolean is_ip6,
-                                NMSettingIP4Config *s_ip4,
-                                NMSettingIP6Config *s_ip6,
-                                guint8 *anycast_addr,
+                                const char *dhcp_client_id,
+                                GByteArray *anycast_addr,
                                 const char *hostname,
                                 const char *orig_path,
                                 const char *orig_contents)
@@ -155,9 +156,7 @@ nm_dhcp_dhclient_create_config (const char *interface,
 			/* Override config file "dhcp-client-id" and use one from the
 			 * connection.
 			 */
-			if (   s_ip4
-			    && nm_setting_ip4_config_get_dhcp_client_id (s_ip4)
-			    && !strncmp (p, CLIENTID_TAG, strlen (CLIENTID_TAG)))
+			if (dhcp_client_id && !strncmp (p, CLIENTID_TAG, strlen (CLIENTID_TAG)))
 				continue;
 
 			/* Override config file hostname and use one from the connection */
@@ -222,13 +221,13 @@ nm_dhcp_dhclient_create_config (const char *interface,
 		g_string_append_c (new_contents, '\n');
 
 	if (is_ip6) {
-		add_ip6_config (new_contents, s_ip6, hostname);
+		add_ip6_config (new_contents, hostname);
 		add_also_request (alsoreq, "dhcp6.name-servers");
 		add_also_request (alsoreq, "dhcp6.domain-search");
 		add_also_request (alsoreq, "dhcp6.client-id");
 		add_also_request (alsoreq, "dhcp6.server-id");
 	} else {
-		add_ip4_config (new_contents, s_ip4, hostname);
+		add_ip4_config (new_contents, dhcp_client_id, hostname);
 		add_also_request (alsoreq, "rfc3442-classless-static-routes");
 		add_also_request (alsoreq, "ms-classless-static-routes");
 		add_also_request (alsoreq, "static-routes");
@@ -247,17 +246,22 @@ nm_dhcp_dhclient_create_config (const char *interface,
 
 	g_string_append_c (new_contents, '\n');
 
-	if (anycast_addr) {
+	if (anycast_addr && anycast_addr->len == 6) {
+		const guint8 *p_anycast_addr = anycast_addr->data;
+
 		g_string_append_printf (new_contents, "interface \"%s\" {\n"
 		                        " initial-interval 1; \n"
 		                        " anycast-mac ethernet %02x:%02x:%02x:%02x:%02x:%02x;\n"
 		                        "}\n",
 		                        interface,
-		                        anycast_addr[0], anycast_addr[1],
-		                        anycast_addr[2], anycast_addr[3],
-		                        anycast_addr[4], anycast_addr[5]);
+		                        p_anycast_addr[0], p_anycast_addr[1],
+		                        p_anycast_addr[2], p_anycast_addr[3],
+		                        p_anycast_addr[4], p_anycast_addr[5]);
 	}
 
+	/* Finally, assert that anycast_addr was unset or a 48 bit mac address. */
+	g_return_val_if_fail (!anycast_addr || anycast_addr->len == 6, g_string_free (new_contents, FALSE));
+
 	return g_string_free (new_contents, FALSE);
 }
 
@@ -423,3 +427,238 @@ nm_dhcp_dhclient_save_duid (const char *leasefile,
 	return success;
 }
 
+static void
+add_lease_option (GHashTable *hash, char *line)
+{
+	char *spc;
+	size_t len;
+
+	/* Find the space after "option" */
+	spc = strchr (line, ' ');
+	if (!spc)
+		return;
+
+	/* Find the option tag's data, which is after the second space */
+	if (g_str_has_prefix (line, "option ")) {
+		while (g_ascii_isspace (*spc))
+			spc++;
+		spc = strchr (spc + 1, ' ');
+		if (!spc)
+			return;
+	}
+
+	/* Split the line at the space */
+	*spc = '\0';
+	spc++;
+
+	/* Kill the ';' at the end of the line, if any */
+	len = strlen (spc);
+	if (*(spc + len - 1) == ';')
+		*(spc + len - 1) = '\0';
+
+	/* Strip leading quote */
+	while (g_ascii_isspace (*spc))
+		spc++;
+	if (*spc == '"')
+		spc++;
+
+	/* Strip trailing quote */
+	len = strlen (spc);
+	if (len > 0 && spc[len - 1] == '"')
+		spc[len - 1] = '\0';
+
+	if (spc[0])
+		g_hash_table_insert (hash, g_strdup (line), g_strdup (spc));
+}
+
+#define LEASE_INVALID    G_MININT64
+static GTimeSpan
+lease_validity_span (const char *str_expire, GDateTime *now)
+{
+	GDateTime *expire = NULL;
+	struct tm expire_tm;
+	GTimeSpan span;
+
+	g_return_val_if_fail (now != NULL, LEASE_INVALID);
+	g_return_val_if_fail (str_expire != NULL, LEASE_INVALID);
+
+	/* Skip initial number (day of week?) */
+	if (!isdigit (*str_expire++))
+		return LEASE_INVALID;
+	if (!isspace (*str_expire++))
+		return LEASE_INVALID;
+	/* Read lease expiration (in UTC) */
+	if (!strptime (str_expire, "%t%Y/%m/%d %H:%M:%S", &expire_tm))
+		return LEASE_INVALID;
+
+	expire = g_date_time_new_utc (expire_tm.tm_year + 1900,
+	                              expire_tm.tm_mon + 1,
+	                              expire_tm.tm_mday,
+	                              expire_tm.tm_hour,
+	                              expire_tm.tm_min,
+	                              expire_tm.tm_sec);
+	if (!expire)
+		return LEASE_INVALID;
+
+	span = g_date_time_difference (expire, now);
+	g_date_time_unref (expire);
+
+	/* GDateTime only supports a range of less then 10000 years, so span can
+	 * not overflow or be equal to LEASE_INVALID */
+	return span;
+}
+
+/**
+ * nm_dhcp_dhclient_read_lease_ip_configs:
+ * @iface: the interface name to match leases with
+ * @contents: the contents of a dhclient leasefile
+ * @ipv6: whether to read IPv4 or IPv6 leases
+ * @now: the current UTC date/time; pass %NULL to automatically use current
+ *  UTC time.  Testcases may need a different value for 'now'
+ *
+ * Reads dhclient leases from @contents and parses them into either
+ * #NMIP4Config or #NMIP6Config objects depending on the value of @ipv6.
+ *
+ * Returns: a #GSList of #NMIP4Config objects (if @ipv6 is %FALSE) or a list of
+ * #NMIP6Config objects (if @ipv6 is %TRUE) containing the lease data.
+ */
+GSList *
+nm_dhcp_dhclient_read_lease_ip_configs (const char *iface,
+                                        const char *contents,
+                                        gboolean ipv6,
+                                        GDateTime *now)
+{
+	GSList *parsed = NULL, *iter, *leases = NULL;
+	char **line, **split = NULL;
+	GHashTable *hash = NULL;
+	gint32 now_monotonic_ts;
+
+	g_return_val_if_fail (contents != NULL, NULL);
+
+	split = g_strsplit_set (contents, "\n\r", -1);
+	if (!split)
+		return NULL;
+
+	for (line = split; line && *line; line++) {
+		*line = g_strstrip (*line);
+
+		if (*line[0] == '#') {
+			/* Comment */
+		} else if (!strcmp (*line, "}")) {
+			/* Lease ends */
+			parsed = g_slist_append (parsed, hash);
+			hash = NULL;
+		} else if (!strcmp (*line, "lease {")) {
+			/* Beginning of a new lease */
+			if (hash) {
+				/* Ignore malformed lease that doesn't end before new one starts */
+				g_hash_table_destroy (hash);
+			}
+
+			hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+		} else if (hash && strlen (*line))
+			add_lease_option (hash, *line);
+	}
+	g_strfreev (split);
+
+	/* Check if the last lease in the file was properly ended */
+	if (hash) {
+		/* Ignore malformed lease that doesn't end before new one starts */
+		g_hash_table_destroy (hash);
+		hash = NULL;
+	}
+
+	if (now)
+		g_date_time_ref (now);
+	else
+		now = g_date_time_new_now_utc ();
+	now_monotonic_ts = nm_utils_get_monotonic_timestamp_s ();
+
+	for (iter = parsed; iter; iter = g_slist_next (iter)) {
+		NMIP4Config *ip4;
+		NMPlatformIP4Address address;
+		const char *value;
+		GTimeSpan expiry;
+		guint32 tmp, gw = 0;
+
+		hash = iter->data;
+
+		/* Make sure this lease is for the interface we want */
+		value = g_hash_table_lookup (hash, "interface");
+		if (!value || strcmp (value, iface))
+			continue;
+
+		value = g_hash_table_lookup (hash, "expire");
+		if (!value)
+			continue;
+		expiry = lease_validity_span (value, now);
+		if (expiry == LEASE_INVALID)
+			continue;
+
+		/* scale expiry to seconds (and CLAMP into the range of guint32) */
+		expiry = CLAMP (expiry / G_TIME_SPAN_SECOND, 0, NM_PLATFORM_LIFETIME_PERMANENT-1);
+		if (expiry <= 0) {
+			/* the address is already expired. Don't even add it. */
+			continue;
+		}
+
+		memset (&address, 0, sizeof (address));
+
+		/* IP4 address */
+		value = g_hash_table_lookup (hash, "fixed-address");
+		if (!value)
+			continue;
+		if (!inet_pton (AF_INET, value, &address.address))
+			continue;
+
+		/* Gateway */
+		value = g_hash_table_lookup (hash, "option routers");
+		if (!value)
+			continue;
+		if (!inet_pton (AF_INET, value, &gw))
+			continue;
+
+		/* Netmask */
+		value = g_hash_table_lookup (hash, "option subnet-mask");
+		if (value && inet_pton (AF_INET, value, &tmp))
+			address.plen = nm_utils_ip4_netmask_to_prefix (tmp);
+
+		/* Get default netmask for the IP according to appropriate class. */
+		if (!address.plen)
+			address.plen = nm_utils_ip4_get_default_prefix (address.address);
+
+		address.timestamp = now_monotonic_ts;
+		address.lifetime = address.preferred = expiry;
+		address.source = NM_PLATFORM_SOURCE_DHCP;
+
+		ip4 = nm_ip4_config_new ();
+		nm_ip4_config_add_address (ip4, &address);
+		nm_ip4_config_set_gateway (ip4, gw);
+
+		value = g_hash_table_lookup (hash, "option domain-name-servers");
+		if (value) {
+			char **dns, **dns_iter;
+
+			dns = g_strsplit_set (value, ",", -1);
+			for (dns_iter = dns; dns_iter && *dns_iter; dns_iter++) {
+				if (inet_pton (AF_INET, *dns_iter, &tmp))
+					nm_ip4_config_add_nameserver (ip4, tmp);
+			}
+			if (dns)
+				g_strfreev (dns);
+		}
+
+		value = g_hash_table_lookup (hash, "option domain-name");
+		if (value && value[0])
+			nm_ip4_config_add_domain (ip4, value);
+
+		/* FIXME: static routes */
+
+		leases = g_slist_append (leases, ip4);
+	}
+
+	g_date_time_unref (now);
+	g_slist_free_full (parsed, (GDestroyNotify) g_hash_table_destroy);
+	return leases;
+}
+
diff --git a/src/dhcp-manager/nm-dhcp-dhclient-utils.h b/src/dhcp-manager/nm-dhcp-dhclient-utils.h
index 95cb0568..e8d91b31 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient-utils.h
+++ b/src/dhcp-manager/nm-dhcp-dhclient-utils.h
@@ -27,9 +27,8 @@
 
 char *nm_dhcp_dhclient_create_config (const char *interface,
                                       gboolean is_ip6,
-                                      NMSettingIP4Config *s_ip4,
-                                      NMSettingIP6Config *s_ip6,
-                                      guint8 *anycast_addr,
+                                      const char *dhcp_client_id,
+                                      GByteArray *anycast_addr,
                                       const char *hostname,
                                       const char *orig_path,
                                       const char *orig_contents);
@@ -44,5 +43,10 @@ gboolean nm_dhcp_dhclient_save_duid (const char *leasefile,
                                      const char *escaped_duid,
                                      GError **error);
 
+GSList *nm_dhcp_dhclient_read_lease_ip_configs (const char *iface,
+                                                const char *contents,
+                                                gboolean ipv6,
+                                                GDateTime *now);
+
 #endif /* NM_DHCP_DHCLIENT_UTILS_H */
 
diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c
index 9a42f0e4..4232ee0c 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient.c
+++ b/src/dhcp-manager/nm-dhcp-dhclient.c
@@ -32,6 +32,7 @@
 #include <stdio.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <ctype.h>
 
 #include <config.h>
 
@@ -39,14 +40,13 @@
 #include "nm-utils.h"
 #include "nm-logging.h"
 #include "nm-dhcp-dhclient-utils.h"
+#include "nm-dhcp-manager.h"
 #include "nm-posix-signals.h"
 
 G_DEFINE_TYPE (NMDHCPDhclient, nm_dhcp_dhclient, NM_TYPE_DHCP_CLIENT)
 
 #define NM_DHCP_DHCLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_DHCLIENT, NMDHCPDhclientPrivate))
 
-#define ACTION_SCRIPT_PATH	LIBEXECDIR "/nm-dhcp-client.action"
-
 typedef struct {
 	const char *path;
 	char *conf_file;
@@ -136,223 +136,37 @@ get_dhclient_leasefile (const char *iface,
 	return NULL;
 }
 
-static void
-add_lease_option (GHashTable *hash, char *line)
-{
-	char *spc;
-
-	spc = strchr (line, ' ');
-	if (!spc) {
-		nm_log_warn (LOGD_DHCP, "DHCP lease file line '%s' did not contain a space", line);
-		return;
-	}
-
-	/* If it's an 'option' line, split at second space */
-	if (g_str_has_prefix (line, "option ")) {
-		spc = strchr (spc + 1, ' ');
-		if (!spc) {
-			nm_log_warn (LOGD_DHCP, "DHCP lease file option line '%s' did not contain a second space",
-			             line);
-			return;
-		}
-	}
-
-	/* Split the line at the space */
-	*spc = '\0';
-	spc++;
-
-	/* Kill the ';' at the end of the line, if any */
-	if (*(spc + strlen (spc) - 1) == ';')
-		*(spc + strlen (spc) - 1) = '\0';
-
-	/* Treat 'interface' specially */
-	if (g_str_has_prefix (line, "interface")) {
-		if (*(spc) == '"')
-			spc++; /* Jump past the " */
-		if (*(spc + strlen (spc) - 1) == '"')
-			*(spc + strlen (spc) - 1) = '\0';  /* Kill trailing " */
-	}
-
-	g_hash_table_insert (hash, g_strdup (line), g_strdup (spc));
-}
-
 GSList *
-nm_dhcp_dhclient_get_lease_config (const char *iface, const char *uuid, gboolean ipv6)
+nm_dhcp_dhclient_get_lease_ip_configs (const char *iface,
+                                       const char *uuid,
+                                       gboolean ipv6)
 {
-	GSList *parsed = NULL, *iter, *leases = NULL;
 	char *contents = NULL;
 	char *leasefile;
-	char **line, **split = NULL;
-	GHashTable *hash = NULL;
-
-	/* IPv6 not supported */
-	if (ipv6)
-		return NULL;
+	GSList *leases = NULL;
 
 	leasefile = get_dhclient_leasefile (iface, uuid, FALSE, NULL);
 	if (!leasefile)
 		return NULL;
 
-	if (!g_file_test (leasefile, G_FILE_TEST_EXISTS))
-		goto out;
-
-	if (!g_file_get_contents (leasefile, &contents, NULL, NULL))
-		goto out;
+	if (   g_file_test (leasefile, G_FILE_TEST_EXISTS)
+	    && g_file_get_contents (leasefile, &contents, NULL, NULL)
+	    && contents
+	    && contents[0])
+		leases = nm_dhcp_dhclient_read_lease_ip_configs (iface, contents, ipv6, NULL);
 
-	split = g_strsplit_set (contents, "\n\r", -1);
+	g_free (leasefile);
 	g_free (contents);
-	if (!split)
-		goto out;
-
-	for (line = split; line && *line; line++) {
-		*line = g_strstrip (*line);
-
-		if (!strcmp (*line, "}")) {
-			/* Lease ends */
-			parsed = g_slist_append (parsed, hash);
-			hash = NULL;
-		} else if (!strcmp (*line, "lease {")) {
-			/* Beginning of a new lease */
-			if (hash) {
-				nm_log_warn (LOGD_DHCP, "DHCP lease file %s malformed; new lease started "
-				             "without ending previous lease",
-				             leasefile);
-				g_hash_table_destroy (hash);
-			}
-
-			hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-		} else if (strlen (*line))
-			add_lease_option (hash, *line);
-	}
-	g_strfreev (split);
-
-	/* Check if the last lease in the file was properly ended */
-	if (hash) {
-		nm_log_warn (LOGD_DHCP, "DHCP lease file %s malformed; new lease started "
-		             "without ending previous lease",
-		             leasefile);
-		g_hash_table_destroy (hash);
-		hash = NULL;
-	}
-
-	for (iter = parsed; iter; iter = g_slist_next (iter)) {
-		NMIP4Config *ip4;
-		NMIP4Address *addr;
-		const char *data;
-		struct in_addr tmp;
-		guint32 prefix;
-		struct tm expire;
-
-		hash = iter->data;
-
-		/* Make sure this lease is for the interface we want */
-		data = g_hash_table_lookup (hash, "interface");
-		if (!data || strcmp (data, iface))
-			continue;
-
-		data = g_hash_table_lookup (hash, "expire");
-		if (data) {
-			time_t now_tt;
-			struct tm *now;
-
-			/* Read lease expiration (in UTC) */
-			if (!strptime (data, "%w %Y/%m/%d %H:%M:%S", &expire)) {
-				nm_log_warn (LOGD_DHCP, "couldn't parse DHCP lease file expire time '%s'",
-				             data);
-				continue;
-			}
-
-			now_tt = time (NULL);
-			now = gmtime(&now_tt);
-
-			/* Ignore this lease if it's already expired */
-			if (expire.tm_year < now->tm_year)
-				continue;
-			else if (expire.tm_year == now->tm_year) {
-				if (expire.tm_mon < now->tm_mon)
-					continue;
-				else if (expire.tm_mon == now->tm_mon) {
-					if (expire.tm_mday < now->tm_mday)
-						continue;
-					else if (expire.tm_mday == now->tm_mday) {
-						if (expire.tm_hour < now->tm_hour)
-							continue;
-						else if (expire.tm_hour == now->tm_hour) {
-							if (expire.tm_min < now->tm_min)
-								continue;
-							else if (expire.tm_min == now->tm_min) {
-								if (expire.tm_sec <= now->tm_sec)
-									continue;
-							}
-						}
-					}
-				}
-			}
-			/* If we get this far, the lease hasn't expired */
-		}
 
-		data = g_hash_table_lookup (hash, "fixed-address");
-		if (!data)
-			continue;
-
-		ip4 = nm_ip4_config_new ();
-		addr = nm_ip4_address_new ();
-
-		/* IP4 address */
-		if (!inet_pton (AF_INET, data, &tmp)) {
-			nm_log_warn (LOGD_DHCP, "couldn't parse DHCP lease file IP4 address '%s'", data);
-			goto error;
-		}
-		nm_ip4_address_set_address (addr, tmp.s_addr);
-
-		/* Netmask */
-		data = g_hash_table_lookup (hash, "option subnet-mask");
-		if (data) {
-			if (!inet_pton (AF_INET, data, &tmp)) {
-				nm_log_warn (LOGD_DHCP, "couldn't parse DHCP lease file IP4 subnet mask '%s'", data);
-				goto error;
-			}
-			prefix = nm_utils_ip4_netmask_to_prefix (tmp.s_addr);
-		} else {
-			/* Get default netmask for the IP according to appropriate class. */
-			prefix = nm_utils_ip4_get_default_prefix (nm_ip4_address_get_address (addr));
-		}
-		nm_ip4_address_set_prefix (addr, prefix);
-
-		/* Gateway */
-		data = g_hash_table_lookup (hash, "option routers");
-		if (data) {
-			if (!inet_pton (AF_INET, data, &tmp)) {
-				nm_log_warn (LOGD_DHCP, "couldn't parse DHCP lease file IP4 gateway '%s'", data);
-				goto error;
-			}
-			nm_ip4_address_set_gateway (addr, tmp.s_addr);
-		}
-
-		nm_ip4_config_take_address (ip4, addr);
-		leases = g_slist_append (leases, ip4);
-		continue;
-
-	error:
-		nm_ip4_address_unref (addr);
-		g_object_unref (ip4);
-	}
-
-out:
-	g_slist_free_full (parsed, (GDestroyNotify) g_hash_table_destroy);
-	g_free (leasefile);
 	return leases;
 }
 
-
-
 static gboolean
 merge_dhclient_config (const char *iface,
                        const char *conf_file,
                        gboolean is_ip6,
-                       NMSettingIP4Config *s_ip4,
-                       NMSettingIP6Config *s_ip6,
-                       guint8 *anycast_addr,
+                       const char *dhcp_client_id,
+                       GByteArray *anycast_addr,
                        const char *hostname,
                        const char *orig_path,
                        GError **error)
@@ -363,7 +177,7 @@ merge_dhclient_config (const char *iface,
 	g_return_val_if_fail (iface != NULL, FALSE);
 	g_return_val_if_fail (conf_file != NULL, FALSE);
 
-	if (g_file_test (orig_path, G_FILE_TEST_EXISTS)) {
+	if (orig_path && g_file_test (orig_path, G_FILE_TEST_EXISTS)) {
 		GError *read_error = NULL;
 
 		if (!g_file_get_contents (orig_path, &orig, NULL, &read_error)) {
@@ -373,7 +187,7 @@ merge_dhclient_config (const char *iface,
 		}
 	}
 
-	new = nm_dhcp_dhclient_create_config (iface, is_ip6, s_ip4, s_ip6, anycast_addr, hostname, orig_path, orig);
+	new = nm_dhcp_dhclient_create_config (iface, is_ip6, dhcp_client_id, anycast_addr, hostname, orig_path, orig);
 	g_assert (new);
 	success = g_file_set_contents (conf_file, new, -1, error);
 	g_free (new);
@@ -383,7 +197,7 @@ merge_dhclient_config (const char *iface,
 }
 
 static char *
-get_dhclient_config (const char * iface, const char *uuid, gboolean ipv6)
+find_existing_config (const char *iface, const char *uuid, gboolean ipv6)
 {
 	char *path;
 
@@ -393,17 +207,20 @@ get_dhclient_config (const char * iface, const char *uuid, gboolean ipv6)
 	 */
 	if (uuid) {
 		path = g_strdup_printf (NMCONFDIR "/dhclient%s-%s.conf", ipv6 ? "6" : "", uuid);
+		nm_log_dbg (ipv6 ? LOGD_DHCP6 : LOGD_DHCP4, "(%s) looking for existing config %s", iface, path);
 		if (g_file_test (path, G_FILE_TEST_EXISTS))
 			return path;
 		g_free (path);
 	}
 
 	path = g_strdup_printf (NMCONFDIR "/dhclient%s-%s.conf", ipv6 ? "6" : "", iface);
+	nm_log_dbg (ipv6 ? LOGD_DHCP6 : LOGD_DHCP4, "(%s) looking for existing config %s", iface, path);
 	if (g_file_test (path, G_FILE_TEST_EXISTS))
 		return path;
 	g_free (path);
 
 	path = g_strdup_printf (NMCONFDIR "/dhclient%s.conf", ipv6 ? "6" : "");
+	nm_log_dbg (ipv6 ? LOGD_DHCP6 : LOGD_DHCP4, "(%s) looking for existing config %s", iface, path);
 	if (g_file_test (path, G_FILE_TEST_EXISTS))
 		return path;
 	g_free (path);
@@ -417,21 +234,25 @@ get_dhclient_config (const char * iface, const char *uuid, gboolean ipv6)
 	 * (including Fedora) don't even provide a default configuration file.
 	 */
 	path = g_strdup_printf (SYSCONFDIR "/dhcp/dhclient%s-%s.conf", ipv6 ? "6" : "", iface);
+	nm_log_dbg (ipv6 ? LOGD_DHCP6 : LOGD_DHCP4, "(%s) looking for existing config %s", iface, path);
 	if (g_file_test (path, G_FILE_TEST_EXISTS))
 		return path;
 	g_free (path);
 
 	path = g_strdup_printf (SYSCONFDIR "/dhclient%s-%s.conf", ipv6 ? "6" : "", iface);
+	nm_log_dbg (ipv6 ? LOGD_DHCP6 : LOGD_DHCP4, "(%s) looking for existing config %s", iface, path);
 	if (g_file_test (path, G_FILE_TEST_EXISTS))
 		return path;
 	g_free (path);
 
 	path = g_strdup_printf (SYSCONFDIR "/dhcp/dhclient%s.conf", ipv6 ? "6" : "");
+	nm_log_dbg (ipv6 ? LOGD_DHCP6 : LOGD_DHCP4, "(%s) looking for existing config %s", iface, path);
 	if (g_file_test (path, G_FILE_TEST_EXISTS))
 		return path;
 	g_free (path);
 
 	path = g_strdup_printf (SYSCONFDIR "/dhclient%s.conf", ipv6 ? "6" : "");
+	nm_log_dbg (ipv6 ? LOGD_DHCP6 : LOGD_DHCP4, "(%s) looking for existing config %s", iface, path);
 	if (g_file_test (path, G_FILE_TEST_EXISTS))
 		return path;
 	g_free (path);
@@ -449,9 +270,9 @@ get_dhclient_config (const char * iface, const char *uuid, gboolean ipv6)
 static char *
 create_dhclient_config (const char *iface,
                         gboolean is_ip6,
-                        NMSettingIP4Config *s_ip4,
-                        NMSettingIP6Config *s_ip6,
-                        guint8 *dhcp_anycast_addr,
+                        const char *uuid,
+                        const char *dhcp_client_id,
+                        GByteArray *dhcp_anycast_addr,
                         const char *hostname)
 {
 	char *orig = NULL, *new = NULL;
@@ -461,11 +282,23 @@ create_dhclient_config (const char *iface,
 	g_return_val_if_fail (iface != NULL, NULL);
 
 	new = g_strdup_printf (NMSTATEDIR "/dhclient%s-%s.conf", is_ip6 ? "6" : "", iface);
+	nm_log_dbg (is_ip6 ? LOGD_DHCP6 : LOGD_DHCP4,
+	            "(%s): creating composite dhclient config %s",
+	            iface, new);
+
+	orig = find_existing_config (iface, uuid, is_ip6);
+	if (orig) {
+		nm_log_dbg (is_ip6 ? LOGD_DHCP6 : LOGD_DHCP4,
+		            "(%s): merging existing dhclient config %s",
+		            iface, orig);
+	} else {
+		nm_log_dbg (is_ip6 ? LOGD_DHCP6 : LOGD_DHCP4,
+		            "(%s): no existing dhclient configuration to merge",
+		            iface);
+	}
 
-	/* TODO: also support UUID */
-	orig = get_dhclient_config (iface, NULL, is_ip6);
 	error = NULL;
-	success = merge_dhclient_config (iface, new, is_ip6, s_ip4, s_ip6, dhcp_anycast_addr, hostname, orig, &error);
+	success = merge_dhclient_config (iface, new, is_ip6, dhcp_client_id, dhcp_anycast_addr, hostname, orig, &error);
 	if (!success) {
 		nm_log_warn (LOGD_DHCP, "(%s): error creating dhclient%s configuration: %s",
 		             iface, is_ip6 ? "6" : "", error->message);
@@ -523,10 +356,6 @@ dhclient_start (NMDHCPClient *client,
 	pid_file = g_strdup_printf (LOCALSTATEDIR "/run/dhclient%s-%s.pid",
 		                        ipv6 ? "6" : "",
 		                        iface);
-	if (!pid_file) {
-		nm_log_warn (log_domain, "(%s): not enough memory for dhcpcd options.", iface);
-		return -1;
-	}
 
 	/* Kill any existing dhclient from the pidfile */
 	binary_name = g_path_get_basename (priv->path);
@@ -593,7 +422,7 @@ dhclient_start (NMDHCPClient *client,
 			g_ptr_array_add (argv, (gpointer) mode_opt);
 	}
 	g_ptr_array_add (argv, (gpointer) "-sf");	/* Set script file */
-	g_ptr_array_add (argv, (gpointer) ACTION_SCRIPT_PATH );
+	g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path);
 
 	if (pid_file) {
 		g_ptr_array_add (argv, (gpointer) "-pf");	/* Set pid file */
@@ -644,16 +473,17 @@ dhclient_start (NMDHCPClient *client,
 
 static GPid
 ip4_start (NMDHCPClient *client,
-           NMSettingIP4Config *s_ip4,
-           guint8 *dhcp_anycast_addr,
+           const char *dhcp_client_id,
+           GByteArray *dhcp_anycast_addr,
            const char *hostname)
 {
 	NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
-	const char *iface;
+	const char *iface, *uuid;
 
 	iface = nm_dhcp_client_get_iface (client);
+	uuid = nm_dhcp_client_get_uuid (client);
 
-	priv->conf_file = create_dhclient_config (iface, FALSE, s_ip4, NULL, dhcp_anycast_addr, hostname);
+	priv->conf_file = create_dhclient_config (iface, FALSE, uuid, dhcp_client_id, dhcp_anycast_addr, hostname);
 	if (!priv->conf_file) {
 		nm_log_warn (LOGD_DHCP4, "(%s): error creating dhclient configuration file.", iface);
 		return -1;
@@ -664,18 +494,18 @@ ip4_start (NMDHCPClient *client,
 
 static GPid
 ip6_start (NMDHCPClient *client,
-           NMSettingIP6Config *s_ip6,
-           guint8 *dhcp_anycast_addr,
+           GByteArray *dhcp_anycast_addr,
            const char *hostname,
            gboolean info_only,
            const GByteArray *duid)
 {
 	NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
-	const char *iface;
+	const char *iface, *uuid;
 
 	iface = nm_dhcp_client_get_iface (client);
+	uuid = nm_dhcp_client_get_uuid (client);
 
-	priv->conf_file = create_dhclient_config (iface, TRUE, NULL, s_ip6, dhcp_anycast_addr, hostname);
+	priv->conf_file = create_dhclient_config (iface, TRUE, uuid, NULL, dhcp_anycast_addr, hostname);
 	if (!priv->conf_file) {
 		nm_log_warn (LOGD_DHCP6, "(%s): error creating dhclient6 configuration file.", iface);
 		return -1;
@@ -693,9 +523,11 @@ stop (NMDHCPClient *client, gboolean release, const GByteArray *duid)
 	NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->stop (client, release, duid);
 
 	if (priv->conf_file)
-		remove (priv->conf_file);
+		if (remove (priv->conf_file) == -1)
+			nm_log_dbg (LOGD_DHCP, "Could not remove dhcp config file \"%s\": %d (%s)", priv->conf_file, errno, g_strerror (errno));
 	if (priv->pid_file) {
-		remove (priv->pid_file);
+		if (remove (priv->pid_file) == -1)
+			nm_log_dbg (LOGD_DHCP, "Could not remove dhcp pid file \"%s\": %d (%s)", priv->pid_file, errno, g_strerror (errno));
 		g_free (priv->pid_file);
 		priv->pid_file = NULL;
 	}
@@ -706,7 +538,7 @@ stop (NMDHCPClient *client, gboolean release, const GByteArray *duid)
 		rpid = dhclient_start (client, NULL, duid, TRUE);
 		if (rpid > 0) {
 			/* Wait a few seconds for the release to happen */
-			nm_dhcp_client_stop_pid (rpid, nm_dhcp_client_get_iface (client), 5);
+			nm_dhcp_client_stop_pid (rpid, nm_dhcp_client_get_iface (client));
 		}
 	}
 }
@@ -727,13 +559,13 @@ get_duid (NMDHCPClient *client)
 	if (leasefile) {
 		nm_log_dbg (LOGD_DHCP, "Looking for DHCPv6 DUID in '%s'.", leasefile);
 		duid = nm_dhcp_dhclient_read_duid (leasefile, &error);
-		g_free (leasefile);
 
 		if (error) {
 			nm_log_warn (LOGD_DHCP, "Failed to read leasefile '%s': (%d) %s",
 			             leasefile, error->code, error->message);
 			g_clear_error (&error);
 		}
+		g_free (leasefile);
 	}
 
 	if (!duid && priv->def_leasefile) {
diff --git a/src/dhcp-manager/nm-dhcp-dhclient.h b/src/dhcp-manager/nm-dhcp-dhclient.h
index 89039189..20219a63 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient.h
+++ b/src/dhcp-manager/nm-dhcp-dhclient.h
@@ -41,7 +41,9 @@ typedef struct {
 
 GType nm_dhcp_dhclient_get_type (void);
 
-GSList *nm_dhcp_dhclient_get_lease_config (const char *iface, const char *uuid, gboolean ipv6);
+GSList *nm_dhcp_dhclient_get_lease_ip_configs (const char *iface,
+                                               const char *uuid,
+                                               gboolean ipv6);
 
 const char *nm_dhcp_dhclient_get_path (const char *try_first);
 
diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c
index f978cccc..acfbee26 100644
--- a/src/dhcp-manager/nm-dhcp-dhcpcd.c
+++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c
@@ -34,6 +34,7 @@
 #include <arpa/inet.h>
 
 #include "nm-dhcp-dhcpcd.h"
+#include "nm-dhcp-manager.h"
 #include "nm-utils.h"
 #include "nm-logging.h"
 #include "nm-posix-signals.h"
@@ -42,8 +43,6 @@ G_DEFINE_TYPE (NMDHCPDhcpcd, nm_dhcp_dhcpcd, NM_TYPE_DHCP_CLIENT)
 
 #define NM_DHCP_DHCPCD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_DHCPCD, NMDHCPDhcpcdPrivate))
 
-#define ACTION_SCRIPT_PATH	LIBEXECDIR "/nm-dhcp-client.action"
-
 typedef struct {
 	const char *path;
 	char *pid_file;
@@ -73,12 +72,6 @@ nm_dhcp_dhcpcd_get_path (const char *try_first)
 	return *path;
 }
 
-GSList *
-nm_dhcp_dhcpcd_get_lease_config (const char *iface, const char *uuid, gboolean ipv6)
-{
-	return NULL;
-}
-
 static void
 dhcpcd_child_setup (gpointer user_data G_GNUC_UNUSED)
 {
@@ -95,8 +88,8 @@ dhcpcd_child_setup (gpointer user_data G_GNUC_UNUSED)
 
 static GPid
 ip4_start (NMDHCPClient *client,
-           NMSettingIP4Config *s_ip4,
-           guint8 *dhcp_anycast_addr,
+           const char *dhcp_client_id,
+           GByteArray *dhcp_anycast_addr,
            const char *hostname)
 {
 	NMDHCPDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (client);
@@ -104,21 +97,16 @@ ip4_start (NMDHCPClient *client,
 	GPid pid = -1;
 	GError *error = NULL;
 	char *pid_contents = NULL, *binary_name, *cmd_str;
-	const char *iface, *uuid;
+	const char *iface;
 
 	g_return_val_if_fail (priv->pid_file == NULL, -1);
 
 	iface = nm_dhcp_client_get_iface (client);
-	uuid = nm_dhcp_client_get_uuid (client);
 
 	/* dhcpcd does not allow custom pidfiles; the pidfile is always
 	 * RUNDIR "dhcpcd-<ifname>.pid".
 	 */
 	priv->pid_file = g_strdup_printf (RUNDIR "/dhcpcd-%s.pid", iface);
-	if (!priv->pid_file) {
-		nm_log_warn (LOGD_DHCP4, "(%s): not enough memory for dhcpcd options.", iface);
-		return -1;
-	}
 
 	if (!g_file_test (priv->path, G_FILE_TEST_EXISTS)) {
 		nm_log_warn (LOGD_DHCP4, "%s does not exist.", priv->path);
@@ -142,7 +130,7 @@ ip4_start (NMDHCPClient *client,
 	g_ptr_array_add (argv, (gpointer) "-G");	/* Let NM handle routing */
 
 	g_ptr_array_add (argv, (gpointer) "-c");	/* Set script file */
-	g_ptr_array_add (argv, (gpointer) ACTION_SCRIPT_PATH );
+	g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path);
 
 #ifdef DHCPCD_SUPPORTS_IPV6
 	/* IPv4-only for now.  NetworkManager knows better than dhcpcd when to
@@ -179,8 +167,7 @@ ip4_start (NMDHCPClient *client,
 
 static GPid
 ip6_start (NMDHCPClient *client,
-           NMSettingIP6Config *s_ip6,
-           guint8 *dhcp_anycast_addr,
+           GByteArray *dhcp_anycast_addr,
            const char *hostname,
            gboolean info_only,
            const GByteArray *duid)
@@ -197,8 +184,10 @@ stop (NMDHCPClient *client, gboolean release, const GByteArray *duid)
 	/* Chain up to parent */
 	NM_DHCP_CLIENT_CLASS (nm_dhcp_dhcpcd_parent_class)->stop (client, release, duid);
 
-	if (priv->pid_file)
-		remove (priv->pid_file);
+	if (priv->pid_file) {
+		if (remove (priv->pid_file) == -1)
+			nm_log_dbg (LOGD_DHCP, "Could not remove dhcp pid file \"%s\": %d (%s)", priv->pid_file, errno, g_strerror (errno));
+	}
 
 	/* FIXME: implement release... */
 }
diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.h b/src/dhcp-manager/nm-dhcp-dhcpcd.h
index c90dcb74..fb6b0628 100644
--- a/src/dhcp-manager/nm-dhcp-dhcpcd.h
+++ b/src/dhcp-manager/nm-dhcp-dhcpcd.h
@@ -41,8 +41,6 @@ typedef struct {
 
 GType nm_dhcp_dhcpcd_get_type (void);
 
-GSList *nm_dhcp_dhcpcd_get_lease_config (const char *iface, const char *uuid, gboolean ipv6);
-
 const char *nm_dhcp_dhcpcd_get_path (const char *try_first);
 
 #endif /* NM_DHCP_DHCPCD_H */
diff --git a/src/dhcp-manager/nm-dhcp-helper.c b/src/dhcp-manager/nm-dhcp-helper.c
new file mode 100644
index 00000000..4ddfafe1
--- /dev/null
+++ b/src/dhcp-manager/nm-dhcp-helper.c
@@ -0,0 +1,345 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2007 - 2013 Red Hat, Inc.
+ */
+
+/* for environ */
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include <config.h>
+
+#include <dbus/dbus.h>
+
+#define NM_DHCP_CLIENT_DBUS_IFACE   "org.freedesktop.nm_dhcp_client"
+
+/**
+ * _dbus_dict_open_write:
+ * @iter: A valid dbus message iterator
+ * @iter_dict: on return, a dict iterator to pass to further dict functions
+ *
+ * Start a dict in a dbus message.  Should be paired with a call to
+ * _dbus_dict_close_write().
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ */
+static dbus_bool_t
+_dbus_dict_open_write (DBusMessageIter *iter, DBusMessageIter *iter_dict)
+{
+	if (!iter || !iter_dict)
+		return FALSE;
+
+	return dbus_message_iter_open_container (iter,
+	                                         DBUS_TYPE_ARRAY,
+	                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+	                                         DBUS_TYPE_STRING_AS_STRING
+	                                         DBUS_TYPE_VARIANT_AS_STRING
+	                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+	                                         iter_dict);
+}
+
+/**
+ * _dbus_dict_close_write:
+ * @iter: valid dbus message iterator, same as passed to _dbus_dict_open_write()
+ * @iter_dict: a dbus dict iterator returned from _dbus_dict_open_write()
+ *
+ * End a dict element in a dbus message.  Should be paired with a call to
+ * _dbus_dict_open_write().
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ */
+static dbus_bool_t
+_dbus_dict_close_write (DBusMessageIter *iter, DBusMessageIter *iter_dict)
+{
+	if (!iter || !iter_dict)
+		return FALSE;
+
+	return dbus_message_iter_close_container (iter, iter_dict);
+}
+
+static dbus_bool_t
+_dbus_add_dict_entry_start (DBusMessageIter *iter_dict,
+                            DBusMessageIter *iter_dict_entry,
+                            const char *key,
+                            const int value_type)
+{
+	if (!dbus_message_iter_open_container (iter_dict, DBUS_TYPE_DICT_ENTRY, NULL, iter_dict_entry))
+		return FALSE;
+
+	if (!dbus_message_iter_append_basic (iter_dict_entry, DBUS_TYPE_STRING, &key))
+		return FALSE;
+
+	return TRUE;
+}
+
+
+static dbus_bool_t
+_dbus_add_dict_entry_end (DBusMessageIter *iter_dict,
+                          DBusMessageIter *iter_dict_entry,
+                          DBusMessageIter *iter_dict_val)
+{
+	if (!dbus_message_iter_close_container (iter_dict_entry, iter_dict_val))
+		return FALSE;
+	if (!dbus_message_iter_close_container (iter_dict, iter_dict_entry))
+		return FALSE;
+
+	return TRUE;
+}
+
+static dbus_bool_t
+_dbus_add_dict_entry_byte_array (DBusMessageIter *iter_dict,
+                                 const char *key,
+                                 const char *value,
+                                 const dbus_uint32_t value_len)
+{
+	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
+	dbus_uint32_t i;
+
+	if (!_dbus_add_dict_entry_start (iter_dict, &iter_dict_entry, key, DBUS_TYPE_ARRAY))
+		return FALSE;
+
+	if (!dbus_message_iter_open_container (&iter_dict_entry,
+	                                       DBUS_TYPE_VARIANT,
+	                                       DBUS_TYPE_ARRAY_AS_STRING
+	                                       DBUS_TYPE_BYTE_AS_STRING,
+	                                       &iter_dict_val))
+		return FALSE;
+
+	if (!dbus_message_iter_open_container (&iter_dict_val,
+	                                       DBUS_TYPE_ARRAY,
+	                                       DBUS_TYPE_BYTE_AS_STRING,
+	                                       &iter_array))
+		return FALSE;
+
+	for (i = 0; i < value_len; i++) {
+		if (!dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_BYTE, &(value[i])))
+			return FALSE;
+	}
+
+	if (!dbus_message_iter_close_container (&iter_dict_val, &iter_array))
+		return FALSE;
+
+	if (!_dbus_add_dict_entry_end (iter_dict, &iter_dict_entry, &iter_dict_val))
+		return FALSE;
+
+	return TRUE;
+}
+
+/**
+ * _dbus_dict_append_byte_array:
+ * @iter_dict: A valid %DBusMessageIter returned from _dbus_dict_open_write()
+ * @key: The key of the dict item
+ * @value: The byte array
+ * @value_len: The length of the byte array, in bytes
+ *
+ * Add a byte array entry to the dict.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ */
+static dbus_bool_t
+_dbus_dict_append_byte_array (DBusMessageIter *iter_dict,
+                              const char *key,
+                              const char *value,
+                              const dbus_uint32_t value_len)
+{
+	if (!key)
+		return FALSE;
+	if (!value && (value_len != 0))
+		return FALSE;
+	return _dbus_add_dict_entry_byte_array (iter_dict, key, value, value_len);
+}
+
+
+static const char * ignore[] = {"PATH", "SHLVL", "_", "PWD", "dhc_dbus", NULL};
+
+static dbus_bool_t
+build_message (DBusMessage * message)
+{
+	char **item;
+	dbus_bool_t success = FALSE;
+	DBusMessageIter iter, iter_dict;
+
+	dbus_message_iter_init_append (message, &iter);
+	if (!_dbus_dict_open_write (&iter, &iter_dict))
+		goto out;
+
+	/* List environment and format for dbus dict */
+	for (item = environ; *item; item++) {
+		char *name, *val, **p;
+
+		/* Split on the = */
+		name = strdup (*item);
+		val = strchr (name, '=');
+		if (!val)
+			goto next;
+		*val++ = '\0';
+		if (!strlen (val))
+			val = NULL;
+
+		/* Ignore non-DCHP-related environment variables */
+		for (p = (char **) ignore; *p; p++) {
+			if (strncmp (name, *p, strlen (*p)) == 0)
+				goto next;
+		}
+
+		/* Value passed as a byte array rather than a string, because there are
+		 * no character encoding guarantees with DHCP, and D-Bus requires
+		 * strings to be UTF-8.
+		 */
+		if (!_dbus_dict_append_byte_array (&iter_dict,
+		                                      name,
+		                                      val ? val : "\0",
+		                                      val ? strlen (val) : 1)) {
+			fprintf (stderr, "Error: failed to add item '%s' to signal\n", name);
+		}
+
+	next:
+		free (name);
+	}
+
+	if (!_dbus_dict_close_write (&iter, &iter_dict))
+		goto out;
+
+	success = TRUE;
+
+out:
+	return success;
+}
+
+#if !HAVE_DBUS_GLIB_100
+static DBusConnection *
+shared_connection_init (void)
+{
+	DBusConnection * connection;
+	DBusError error;
+	int ret;
+
+	dbus_connection_set_change_sigpipe (TRUE);
+
+	dbus_error_init (&error);
+	connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
+	if (dbus_error_is_set (&error)) {
+		fprintf (stderr, "Error: could not get the system bus.  Make sure "
+		            "the message bus daemon is running!  Message: (%s) %s\n",
+		            error.name,
+		            error.message);
+		goto error;
+	}
+
+	dbus_error_init (&error);
+	ret = dbus_bus_request_name (connection, "org.freedesktop.nm_dhcp_client", 0, &error);
+	if (dbus_error_is_set (&error)) {
+		fprintf (stderr, "Error: Could not acquire the NM DHCP client service. "
+		            "Message: (%s) %s\n",
+		            error.name,
+		            error.message);
+		goto error;
+	}
+
+	if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+		fprintf (stderr, "Error: Could not acquire the NM DHCP client service "
+		         "as it is already taken.  Return: %d\n",
+		         ret);
+		goto error;
+	}
+
+	return connection;
+
+error:
+	if (dbus_error_is_set (&error))
+		dbus_error_free (&error);
+	if (connection)
+		dbus_connection_unref (connection);
+	return NULL;
+}
+#endif
+
+static void
+fatal_error (void)
+{
+	const char *pid_str = getenv ("pid");
+	int pid = 0;
+
+	if (pid_str)
+		pid = strtol (pid_str, NULL, 10);
+	if (pid) {
+		fprintf (stderr, "Fatal error occured, killing dhclient instance with pid %d.\n", pid);
+		kill (pid, SIGTERM);
+	}
+
+	exit (1);
+}
+
+int
+main (int argc, char *argv[])
+{
+	DBusConnection *connection;
+	DBusMessage *message;
+	dbus_bool_t result;
+	DBusError error;
+
+	dbus_connection_set_change_sigpipe (TRUE);
+
+	dbus_error_init (&error);
+	connection = dbus_connection_open_private ("unix:path=" NMRUNDIR "/private-dhcp", &error);
+	if (!connection) {
+#if !HAVE_DBUS_GLIB_100
+		connection = shared_connection_init ();
+#endif
+		if (!connection) {
+			fprintf (stderr, "Error: could not connect to NetworkManager DBus socket: (%s) %s\n",
+				     error.name, error.message);
+			dbus_error_free (&error);
+			fatal_error ();
+		}
+	}
+	dbus_connection_set_exit_on_disconnect (connection, FALSE);
+
+	message = dbus_message_new_signal ("/", NM_DHCP_CLIENT_DBUS_IFACE, "Event");
+	if (message == NULL) {
+		fprintf (stderr, "Error: Not enough memory to send DHCP Event signal.\n");
+		fatal_error ();
+	}
+
+	/* Dump environment variables into the message */
+	result = build_message (message);
+	if (result == FALSE) {
+		fprintf (stderr, "Error: Not enough memory to send DHCP Event signal.\n");
+		fatal_error ();
+	}
+
+	/* queue the message */
+	result = dbus_connection_send (connection, message, NULL);
+	if (!result) {
+		fprintf (stderr, "Error: Could not send send DHCP Event signal.\n");
+		fatal_error ();
+	}
+	dbus_message_unref (message);
+
+	/* Send out the message */
+	dbus_connection_flush (connection);
+
+	return 0;
+}
+
diff --git a/src/dhcp-manager/nm-dhcp-helper.conf b/src/dhcp-manager/nm-dhcp-helper.conf
new file mode 100644
index 00000000..0aeae603
--- /dev/null
+++ b/src/dhcp-manager/nm-dhcp-helper.conf
@@ -0,0 +1,13 @@
+<!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"/>
+        </policy>
+        <policy context="default">
+                <deny own="org.freedesktop.nm_dhcp_client"/>
+		<deny send_destination="org.freedesktop.nm_dhcp_client"/>
+        </policy>
+</busconfig>
+
diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c
index d40eb48d..ab6966cb 100644
--- a/src/dhcp-manager/nm-dhcp-manager.c
+++ b/src/dhcp-manager/nm-dhcp-manager.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2005 - 2010 Red Hat, Inc.
+ * Copyright (C) 2005 - 2013 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  *
  */
@@ -37,12 +37,12 @@
 #include "nm-dhcp-manager.h"
 #include "nm-dhcp-dhclient.h"
 #include "nm-dhcp-dhcpcd.h"
-#include "nm-marshal.h"
 #include "nm-logging.h"
 #include "nm-dbus-manager.h"
-#include "nm-hostname-provider.h"
+#include "nm-config.h"
 #include "nm-dbus-glib-types.h"
 #include "nm-glib-compat.h"
+#include "NetworkManagerUtils.h"
 
 GQuark
 nm_dhcp_manager_error_quark (void)
@@ -55,23 +55,30 @@ nm_dhcp_manager_error_quark (void)
     return ret;
 }
 
-#define NM_DHCP_CLIENT_DBUS_SERVICE "org.freedesktop.nm_dhcp_client"
 #define NM_DHCP_CLIENT_DBUS_IFACE   "org.freedesktop.nm_dhcp_client"
 
 #define DHCP_TIMEOUT 45 /* default DHCP timeout, in seconds */
 
-static NMDHCPManager *singleton = NULL;
+#define PRIV_SOCK_PATH NMRUNDIR "/private-dhcp"
+#define PRIV_SOCK_TAG  "dhcp"
+
+/* default to installed helper, but can be modified for testing */
+const char *nm_dhcp_helper_path = LIBEXECDIR "/nm-dhcp-helper";
 
 typedef GSList * (*GetLeaseConfigFunc) (const char *iface, const char *uuid, gboolean ipv6);
 
 typedef struct {
 	GType               client_type;
-	GetLeaseConfigFunc  get_lease_config_func;
+	GetLeaseConfigFunc  get_lease_ip_configs_func;
 
 	NMDBusManager *     dbus_mgr;
+	guint               new_conn_id;
+	guint               dis_conn_id;
+	GHashTable *        proxies;
+
 	GHashTable *        clients;
 	DBusGProxy *        proxy;
-	NMHostnameProvider *hostname_provider;
+	char *              default_hostname;
 } NMDHCPManagerPrivate;
 
 
@@ -119,7 +126,6 @@ get_client_for_pid (NMDHCPManager *manager, GPid pid)
 	GHashTableIter iter;
 	gpointer value;
 
-	g_return_val_if_fail (manager != NULL, NULL);
 	g_return_val_if_fail (NM_IS_DHCP_MANAGER (manager), NULL);
 
 	priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
@@ -144,7 +150,6 @@ get_client_for_iface (NMDHCPManager *manager,
 	GHashTableIter iter;
 	gpointer value;
 
-	g_return_val_if_fail (manager != NULL, NULL);
 	g_return_val_if_fail (NM_IS_DHCP_MANAGER (manager), NULL);
 	g_return_val_if_fail (iface, NULL);
 
@@ -186,50 +191,46 @@ nm_dhcp_manager_handle_event (DBusGProxy *proxy,
                               GHashTable *options,
                               gpointer user_data)
 {
-	NMDHCPManager *manager;
-	NMDHCPManagerPrivate *priv;
+	NMDHCPManager *manager = NM_DHCP_MANAGER (user_data);
 	NMDHCPClient *client;
 	char *iface = NULL;
 	char *pid_str = NULL;
 	char *reason = NULL;
-	unsigned long temp;
-
-	manager = NM_DHCP_MANAGER (user_data);
-	priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
+	long pid;
 
 	iface = get_option (options, "interface");
 	if (iface == NULL) {
-		nm_log_warn (LOGD_DHCP, "DHCP event didn't have associated interface.");
+		nm_log_warn (LOGD_DHCP, "DHCP event: didn't have associated interface.");
 		goto out;
 	}
 
 	pid_str = get_option (options, "pid");
-	if (pid_str == NULL) {
-		nm_log_warn (LOGD_DHCP, "DHCP event didn't have associated PID.");
-		goto out;
-	}
-
-	temp = strtoul (pid_str, NULL, 10);
-	if ((temp == ULONG_MAX) && (errno == ERANGE)) {
-		nm_log_warn (LOGD_DHCP, "couldn't convert PID");
+	pid = nm_utils_ascii_str_to_int64 (pid_str, 10, 0, LONG_MAX, -1);
+	if (pid == -1 || pid != (GPid)pid) {
+		nm_log_warn (LOGD_DHCP, "DHCP event: couldn't convert PID '%s' to an integer", pid_str ? pid_str : "(null)");
 		goto out;
 	}
 
-	client = get_client_for_pid (manager, (GPid) temp);
+	reason = get_option (options, "reason");
+	client = get_client_for_pid (manager, (GPid) pid);
 	if (client == NULL) {
-		nm_log_warn (LOGD_DHCP, "(pid %ld) unhandled DHCP event for interface %s", temp, iface);
+		if (reason && g_ascii_strcasecmp (reason, "RELEASE") == 0) {
+			/* This happens regularly, when the dhcp client gets killed and we receive its last message.
+			 * Don't log a warning in this case. */
+			nm_log_dbg (LOGD_DHCP, "(pid %ld) unhandled RELEASE DHCP event for interface %s", pid, iface);
+		} else
+			nm_log_warn (LOGD_DHCP, "(pid %ld) unhandled DHCP event for interface %s", pid, iface);
 		goto out;
 	}
 
 	if (strcmp (iface, nm_dhcp_client_get_iface (client))) {
 		nm_log_warn (LOGD_DHCP, "(pid %ld) received DHCP event from unexpected interface '%s' (expected '%s')",
-		             temp, iface, nm_dhcp_client_get_iface (client));
+		             pid, iface, nm_dhcp_client_get_iface (client));
 		goto out;
 	}
 
-	reason = get_option (options, "reason");
 	if (reason == NULL) {
-		nm_log_warn (LOGD_DHCP, "(pid %ld) DHCP event didn't have a reason", temp);
+		nm_log_warn (LOGD_DHCP, "(pid %ld) DHCP event didn't have a reason", pid);
 		goto out;
 	}
 
@@ -241,6 +242,48 @@ out:
 	g_free (reason);
 }
 
+#if HAVE_DBUS_GLIB_100
+static void
+new_connection_cb (NMDBusManager *mgr,
+                   DBusGConnection *connection,
+                   NMDHCPManager *self)
+{
+	NMDHCPManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
+	DBusGProxy *proxy;
+
+	/* Create a new proxy for the client */
+	proxy = dbus_g_proxy_new_for_peer (connection, "/", NM_DHCP_CLIENT_DBUS_IFACE);
+	dbus_g_proxy_add_signal (proxy,
+	                         "Event",
+	                         DBUS_TYPE_G_MAP_OF_VARIANT,
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (proxy,
+	                             "Event",
+	                             G_CALLBACK (nm_dhcp_manager_handle_event),
+	                             self,
+	                             NULL);
+	g_hash_table_insert (priv->proxies, connection, proxy);
+}
+
+static void
+dis_connection_cb (NMDBusManager *mgr,
+                   DBusGConnection *connection,
+                   NMDHCPManager *self)
+{
+	NMDHCPManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
+	DBusGProxy *proxy;
+
+	proxy = g_hash_table_lookup (priv->proxies, connection);
+	if (proxy) {
+		dbus_g_proxy_disconnect_signal (proxy,
+		                                "Event",
+		                                G_CALLBACK (nm_dhcp_manager_handle_event),
+		                                self);
+		g_hash_table_remove (priv->proxies, connection);
+	}
+}
+#endif
+
 static GType
 get_client_type (const char *client, GError **error)
 {
@@ -250,8 +293,10 @@ get_client_type (const char *client, GError **error)
 	/* If a client was disabled at build-time, its *_PATH define will be
 	 * an empty string.
 	 */
+	/* coverity[array_null] */
 	if (DHCLIENT_PATH && strlen (DHCLIENT_PATH))
 		dhclient_path = nm_dhcp_dhclient_get_path (DHCLIENT_PATH);
+	/* coverity[array_null] */
 	if (DHCPCD_PATH && strlen (DHCPCD_PATH))
 		dhcpcd_path = nm_dhcp_dhcpcd_get_path (DHCPCD_PATH);
 
@@ -264,7 +309,7 @@ get_client_type (const char *client, GError **error)
 			g_set_error_literal (error,
 			                     NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT,
 			                     _("no usable DHCP client could be found."));
-			return 0;
+			return G_TYPE_INVALID;
 		}
 	}
 
@@ -273,7 +318,7 @@ get_client_type (const char *client, GError **error)
 			g_set_error_literal (error,
 			                     NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT,
 			                     _("'dhclient' could be found."));
-			return 0;
+			return G_TYPE_INVALID;
 		}
 		return NM_TYPE_DHCP_DHCLIENT;
 	}
@@ -283,7 +328,7 @@ get_client_type (const char *client, GError **error)
 			g_set_error_literal (error,
 			                     NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT,
 			                     _("'dhcpcd' could be found."));
-			return 0;
+			return G_TYPE_INVALID;
 		}
 		return NM_TYPE_DHCP_DHCPCD;
 	}
@@ -291,54 +336,7 @@ get_client_type (const char *client, GError **error)
 	g_set_error (error,
 	             NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT,
 	             _("unsupported DHCP client '%s'"), client);
-	return 0;
-}
-
-NMDHCPManager *
-nm_dhcp_manager_new (const char *client, GError **error)
-{
-	NMDHCPManagerPrivate *priv;
-	DBusGConnection *g_connection;
-
-	g_warn_if_fail (singleton == NULL);
-
-	singleton = g_object_new (NM_TYPE_DHCP_MANAGER, NULL);
-	priv = NM_DHCP_MANAGER_GET_PRIVATE (singleton);
-
-	/* Client-specific setup */
-	priv->client_type = get_client_type (client, error);
-	if (priv->client_type == NM_TYPE_DHCP_DHCLIENT)
-		priv->get_lease_config_func = nm_dhcp_dhclient_get_lease_config;
-	else if (priv->client_type == NM_TYPE_DHCP_DHCPCD)
-		priv->get_lease_config_func = nm_dhcp_dhcpcd_get_lease_config;
-	else {
-		nm_log_warn (LOGD_DHCP, "No usable DHCP client found! DHCP configurations will fail.");
-	}
-
-	priv->clients = g_hash_table_new_full (g_direct_hash, g_direct_equal,
-	                                       NULL,
-	                                       (GDestroyNotify) g_object_unref);
-	g_assert (priv->clients);
-
-	priv->dbus_mgr = nm_dbus_manager_get ();
-	g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
-	priv->proxy = dbus_g_proxy_new_for_name (g_connection,
-	                                         NM_DHCP_CLIENT_DBUS_SERVICE,
-	                                         "/",
-	                                         NM_DHCP_CLIENT_DBUS_IFACE);
-	g_assert (priv->proxy);
-
-	dbus_g_proxy_add_signal (priv->proxy,
-	                         "Event",
-	                         DBUS_TYPE_G_MAP_OF_VARIANT,
-	                         G_TYPE_INVALID);
-
-	dbus_g_proxy_connect_signal (priv->proxy, "Event",
-	                             G_CALLBACK (nm_dhcp_manager_handle_event),
-	                             singleton,
-	                             NULL);
-
-	return singleton;
+	return G_TYPE_INVALID;
 }
 
 #define REMOVE_ID_TAG "remove-id"
@@ -372,10 +370,10 @@ add_client (NMDHCPManager *self, NMDHCPClient *client)
 	NMDHCPManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
 	guint id;
 
-	id = g_signal_connect_swapped (client, "remove", G_CALLBACK (remove_client), self);
+	id = g_signal_connect_swapped (client, NM_DHCP_CLIENT_SIGNAL_REMOVE, G_CALLBACK (remove_client), self);
 	g_object_set_data (G_OBJECT (client), REMOVE_ID_TAG, GUINT_TO_POINTER (id));
 
-	id = g_signal_connect_swapped (client, "timeout", G_CALLBACK (remove_client), self);
+	id = g_signal_connect_swapped (client, NM_DHCP_CLIENT_SIGNAL_TIMEOUT, G_CALLBACK (remove_client), self);
 	g_object_set_data (G_OBJECT (client), TIMEOUT_ID_TAG, GUINT_TO_POINTER (id));
 
 	g_hash_table_insert (priv->clients, client, g_object_ref (client));
@@ -386,11 +384,11 @@ client_start (NMDHCPManager *self,
               const char *iface,
               const GByteArray *hwaddr,
               const char *uuid,
+              guint priority,
               gboolean ipv6,
-              NMSettingIP4Config *s_ip4,
-              NMSettingIP6Config *s_ip6,
+              const char *dhcp_client_id,
               guint32 timeout,
-              guint8 *dhcp_anycast_addr,
+              GByteArray *dhcp_anycast_addr,
               const char *hostname,
               gboolean info_only)
 {
@@ -421,15 +419,16 @@ client_start (NMDHCPManager *self,
 	                       NM_DHCP_CLIENT_HWADDR, hwaddr,
 	                       NM_DHCP_CLIENT_IPV6, ipv6,
 	                       NM_DHCP_CLIENT_UUID, uuid,
+	                       NM_DHCP_CLIENT_PRIORITY, priority,
 	                       NM_DHCP_CLIENT_TIMEOUT, timeout ? timeout : DHCP_TIMEOUT,
 	                       NULL);
 	g_return_val_if_fail (client != NULL, NULL);
 	add_client (self, client);
 
 	if (ipv6)
-		success = nm_dhcp_client_start_ip6 (client, s_ip6, dhcp_anycast_addr, hostname, info_only);
+		success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, hostname, info_only);
 	else
-		success = nm_dhcp_client_start_ip4 (client, s_ip4, dhcp_anycast_addr, hostname);
+		success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname);
 
 	if (!success) {
 		remove_client (self, client);
@@ -440,54 +439,42 @@ client_start (NMDHCPManager *self,
 	return client;
 }
 
+static const char *
+get_send_hostname (NMDHCPManager *self, const char *setting_hostname)
+{
+	NMDHCPManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
+
+	/* Always prefer the explicit dhcp-send-hostname if given */
+	return setting_hostname ? setting_hostname : priv->default_hostname;
+}
+
 /* Caller owns a reference to the NMDHCPClient on return */
 NMDHCPClient *
 nm_dhcp_manager_start_ip4 (NMDHCPManager *self,
                            const char *iface,
                            const GByteArray *hwaddr,
                            const char *uuid,
+                           guint priority,
                            NMSettingIP4Config *s_ip4,
                            guint32 timeout,
-                           guint8 *dhcp_anycast_addr)
+                           GByteArray *dhcp_anycast_addr)
 {
-	NMDHCPManagerPrivate *priv;
-	const char *hostname = NULL;
-	gboolean send_hostname = TRUE;
+	const char *hostname = NULL, *method;
+	gboolean send_hostname;
 
 	g_return_val_if_fail (self, NULL);
 	g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL);
 
-	priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
-
-	if (s_ip4) {
-		const char *method = nm_setting_ip4_config_get_method (s_ip4);
-
-		if (method) {
-			/* Method must be 'auto' */
-			g_return_val_if_fail (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0, NULL);
-		}
-
-		send_hostname = nm_setting_ip4_config_get_dhcp_send_hostname (s_ip4);
-		if (send_hostname)
-			hostname = nm_setting_ip4_config_get_dhcp_hostname (s_ip4);
-	}
+	method = nm_setting_ip4_config_get_method (s_ip4);
+	g_return_val_if_fail (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0, NULL);
 
-	if (send_hostname) {
-		/* If we're supposed to send the hostname to the DHCP server but
-		 * the user didn't specify one, then use the hostname from the
-		 * hostname provider if there is one, otherwise use the persistent
-		 * hostname.
-		 */
-		if (!hostname && priv->hostname_provider) {
-			hostname = nm_hostname_provider_get_hostname (priv->hostname_provider);
-			if (   hostname
-			    && (!strcmp (hostname, "localhost.localdomain") ||
-			        !strcmp (hostname, "localhost6.localdomain6")))
-				hostname = NULL;
-		}
-	}
+	send_hostname = nm_setting_ip4_config_get_dhcp_send_hostname (s_ip4);
+	if (send_hostname)
+		hostname = get_send_hostname (self, nm_setting_ip4_config_get_dhcp_hostname (s_ip4));
 
-	return client_start (self, iface, hwaddr, uuid, FALSE, s_ip4, NULL, timeout, dhcp_anycast_addr, hostname, FALSE);
+	return client_start (self, iface, hwaddr, uuid, priority, FALSE,
+	                     nm_setting_ip4_config_get_dhcp_client_id (s_ip4),
+	                     timeout, dhcp_anycast_addr, hostname, FALSE);
 }
 
 /* Caller owns a reference to the NMDHCPClient on return */
@@ -496,63 +483,42 @@ nm_dhcp_manager_start_ip6 (NMDHCPManager *self,
                            const char *iface,
                            const GByteArray *hwaddr,
                            const char *uuid,
+                           guint priority,
                            NMSettingIP6Config *s_ip6,
                            guint32 timeout,
-                           guint8 *dhcp_anycast_addr,
+                           GByteArray *dhcp_anycast_addr,
                            gboolean info_only)
 {
-	NMDHCPManagerPrivate *priv;
-	const char *hostname = NULL;
+	const char *hostname;
 
-	g_return_val_if_fail (self, NULL);
 	g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL);
 
-	priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
-
-	if (s_ip6)
-		hostname = nm_setting_ip6_config_get_dhcp_hostname (s_ip6);
-	if (!hostname && priv->hostname_provider) {
-		hostname = nm_hostname_provider_get_hostname (priv->hostname_provider);
-		if (   g_strcmp0 (hostname, "localhost.localdomain") == 0
-		    || g_strcmp0 (hostname, "localhost6.localdomain6") == 0)
-			hostname = NULL;
-	}
-
-	return client_start (self, iface, hwaddr, uuid, TRUE, NULL, s_ip6, timeout, dhcp_anycast_addr, hostname, info_only);
-}
+	hostname = get_send_hostname (self, nm_setting_ip6_config_get_dhcp_hostname (s_ip6));
 
-static void
-hostname_provider_destroyed (gpointer data, GObject *destroyed_object)
-{
-	NM_DHCP_MANAGER_GET_PRIVATE (data)->hostname_provider = NULL;
+	return client_start (self, iface, hwaddr, uuid, priority, TRUE,
+	                     NULL, timeout, dhcp_anycast_addr, hostname, info_only);
 }
 
 void
-nm_dhcp_manager_set_hostname_provider (NMDHCPManager *manager,
-									   NMHostnameProvider *provider)
+nm_dhcp_manager_set_default_hostname (NMDHCPManager *manager, const char *hostname)
 {
-	NMDHCPManagerPrivate *priv;
-
-	g_return_if_fail (NM_IS_DHCP_MANAGER (manager));
+	NMDHCPManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
 
-	priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
+	g_clear_pointer (&priv->default_hostname, g_free);
 
-	if (priv->hostname_provider) {
-		g_object_weak_unref (G_OBJECT (priv->hostname_provider), hostname_provider_destroyed, manager);
-		priv->hostname_provider = NULL;
-	}
+	/* Never send 'localhost'-type names to the DHCP server */
+	if (g_strcmp0 (hostname, "localhost.localdomain") == 0 ||
+	    g_strcmp0 (hostname, "localhost6.localdomain6") == 0)
+		return;
 
-	if (provider) {
-		priv->hostname_provider = provider;
-		g_object_weak_ref (G_OBJECT (provider), hostname_provider_destroyed, manager);
-	}
+	priv->default_hostname = g_strdup (hostname);
 }
 
 GSList *
-nm_dhcp_manager_get_lease_config (NMDHCPManager *self,
-                                  const char *iface,
-                                  const char *uuid,
-                                  gboolean ipv6)
+nm_dhcp_manager_get_lease_ip_configs (NMDHCPManager *self,
+                                      const char *iface,
+                                      const char *uuid,
+                                      gboolean ipv6)
 {
 	NMDHCPManagerPrivate *priv;
 
@@ -562,10 +528,8 @@ nm_dhcp_manager_get_lease_config (NMDHCPManager *self,
 
 	priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
 
-	if (priv->get_lease_config_func)
-		return priv->get_lease_config_func (iface, uuid, ipv6);
-
-	nm_log_warn (LOGD_DHCP, "Cannot get a DHCP lease config (no usable DHCP client was found!)");
+	if (priv->get_lease_ip_configs_func)
+		return priv->get_lease_ip_configs_func (iface, uuid, ipv6);
 	return NULL;
 }
 
@@ -603,13 +567,70 @@ nm_dhcp_manager_test_ip4_options_to_config (const char *dhcp_client,
 NMDHCPManager *
 nm_dhcp_manager_get (void)
 {
-	g_warn_if_fail (singleton != NULL);
-	return g_object_ref (singleton);
+	static NMDHCPManager *singleton = NULL;
+
+	if (G_UNLIKELY (singleton == NULL))
+		singleton = g_object_new (NM_TYPE_DHCP_MANAGER, NULL);
+	g_assert (singleton);
+	return singleton;
 }
 
 static void
-nm_dhcp_manager_init (NMDHCPManager *manager)
+nm_dhcp_manager_init (NMDHCPManager *self)
 {
+	NMDHCPManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
+	const char *client;
+	GError *error = NULL;
+#if !HAVE_DBUS_GLIB_100
+	DBusGConnection *g_connection;
+#endif
+
+	/* Maps DBusGConnection :: DBusGProxy */
+	priv->proxies = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
+
+	/* Client-specific setup */
+	client = nm_config_get_dhcp_client (nm_config_get ());
+	priv->client_type = get_client_type (client, &error);
+
+	if (priv->client_type == NM_TYPE_DHCP_DHCLIENT)
+		priv->get_lease_ip_configs_func = nm_dhcp_dhclient_get_lease_ip_configs;
+	else if (priv->client_type == G_TYPE_INVALID) {
+		nm_log_warn (LOGD_DHCP, "No usable DHCP client found (%s)! DHCP configurations will fail.",
+		             error->message);
+	}
+	g_clear_error (&error);
+
+	priv->clients = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+	                                       NULL,
+	                                       (GDestroyNotify) g_object_unref);
+	g_assert (priv->clients);
+
+	priv->dbus_mgr = nm_dbus_manager_get ();
+
+#if HAVE_DBUS_GLIB_100
+	/* Register the socket our DHCP clients will return lease info on */
+	nm_dbus_manager_private_server_register (priv->dbus_mgr, PRIV_SOCK_PATH, PRIV_SOCK_TAG);
+	priv->new_conn_id = g_signal_connect (priv->dbus_mgr,
+	                                      NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG,
+	                                      (GCallback) new_connection_cb,
+	                                      self);
+	priv->dis_conn_id = g_signal_connect (priv->dbus_mgr,
+	                                      NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "::" PRIV_SOCK_TAG,
+	                                      (GCallback) dis_connection_cb,
+	                                      self);
+#else
+	g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
+	priv->proxy = dbus_g_proxy_new_for_name (g_connection,
+	                                         "org.freedesktop.nm_dhcp_client",
+	                                         "/",
+	                                         NM_DHCP_CLIENT_DBUS_IFACE);
+	g_assert (priv->proxy);
+	dbus_g_proxy_add_signal (priv->proxy, "Event", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->proxy, "Event",
+	                             G_CALLBACK (nm_dhcp_manager_handle_event),
+	                             self,
+	                             NULL);
+#endif
 }
 
 static void
@@ -625,6 +646,23 @@ dispose (GObject *object)
 		g_list_free (values);
 	}
 
+	if (priv->new_conn_id) {
+		g_signal_handler_disconnect (priv->dbus_mgr, priv->new_conn_id);
+		priv->new_conn_id = 0;
+	}
+	if (priv->dis_conn_id) {
+		g_signal_handler_disconnect (priv->dbus_mgr, priv->dis_conn_id);
+		priv->dis_conn_id = 0;
+	}
+	priv->dbus_mgr = NULL;
+
+	if (priv->proxies) {
+		g_hash_table_destroy (priv->proxies);
+		priv->proxies = NULL;
+	}
+	if (priv->proxy)
+		g_object_unref (priv->proxy);
+
 	G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->dispose (object);
 }
 
@@ -633,17 +671,10 @@ finalize (GObject *object)
 {
 	NMDHCPManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (object);
 
-	if (priv->hostname_provider) {
-		g_object_weak_unref (G_OBJECT (priv->hostname_provider), hostname_provider_destroyed, object);
-		priv->hostname_provider = NULL;
-	}
+	g_free (priv->default_hostname);
 
 	if (priv->clients)
 		g_hash_table_destroy (priv->clients);
-	if (priv->proxy)
-		g_object_unref (priv->proxy);
-	if (priv->dbus_mgr)
-		g_object_unref (priv->dbus_mgr);
 
 	G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->finalize (object);
 }
@@ -659,4 +690,3 @@ nm_dhcp_manager_class_init (NMDHCPManagerClass *manager_class)
 	object_class->finalize = finalize;
 	object_class->dispose = dispose;
 }
-
diff --git a/src/dhcp-manager/nm-dhcp-manager.h b/src/dhcp-manager/nm-dhcp-manager.h
index a29a33fd..efdd4378 100644
--- a/src/dhcp-manager/nm-dhcp-manager.h
+++ b/src/dhcp-manager/nm-dhcp-manager.h
@@ -31,7 +31,6 @@
 #include "nm-dhcp-client.h"
 #include "nm-ip4-config.h"
 #include "nm-dhcp4-config.h"
-#include "nm-hostname-provider.h"
 
 typedef enum {
 	NM_DHCP_MANAGER_ERROR_BAD_CLIENT = 0, /*< nick=BadClient >*/
@@ -60,32 +59,34 @@ typedef struct {
 
 GType nm_dhcp_manager_get_type (void);
 
-NMDHCPManager *nm_dhcp_manager_get                  (void);
+NMDHCPManager *nm_dhcp_manager_get (void);
 
-void           nm_dhcp_manager_set_hostname_provider(NMDHCPManager *manager,
-													 NMHostnameProvider *provider);
+void           nm_dhcp_manager_set_default_hostname (NMDHCPManager *manager,
+                                                     const char *hostname);
 
 NMDHCPClient * nm_dhcp_manager_start_ip4     (NMDHCPManager *manager,
                                               const char *iface,
                                               const GByteArray *hwaddr,
                                               const char *uuid,
+                                              guint priority,
                                               NMSettingIP4Config *s_ip4,
                                               guint32 timeout,
-                                              guint8 *dhcp_anycast_addr);
+                                              GByteArray *dhcp_anycast_addr);
 
 NMDHCPClient * nm_dhcp_manager_start_ip6     (NMDHCPManager *manager,
                                               const char *iface,
                                               const GByteArray *hwaddr,
                                               const char *uuid,
+                                              guint priority,
                                               NMSettingIP6Config *s_ip6,
                                               guint32 timeout,
-                                              guint8 *dhcp_anycast_addr,
+                                              GByteArray *dhcp_anycast_addr,
                                               gboolean info_only);
 
-GSList *       nm_dhcp_manager_get_lease_config (NMDHCPManager *self,
-                                                 const char *iface,
-                                                 const char *uuid,
-                                                 gboolean ipv6);
+GSList *       nm_dhcp_manager_get_lease_ip_configs (NMDHCPManager *self,
+                                                     const char *iface,
+                                                     const char *uuid,
+                                                     gboolean ipv6);
 
 /* For testing only */
 NMIP4Config *nm_dhcp_manager_test_ip4_options_to_config (const char *dhcp_client,
@@ -93,7 +94,6 @@ NMIP4Config *nm_dhcp_manager_test_ip4_options_to_config (const char *dhcp_client
                                                          GHashTable *options,
                                                          const char *reason);
 
-/* Only for main.c */
-NMDHCPManager *nm_dhcp_manager_new (const char *client, GError **error);
+extern const char* nm_dhcp_helper_path;
 
 #endif /* NM_DHCP_MANAGER_H */
diff --git a/src/dhcp-manager/tests/Makefile.am b/src/dhcp-manager/tests/Makefile.am
index bf859fe7..6ef828d5 100644
--- a/src/dhcp-manager/tests/Makefile.am
+++ b/src/dhcp-manager/tests/Makefile.am
@@ -1,12 +1,15 @@
-if ENABLE_TESTS
-
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/include \
 	-I$(top_builddir)/include \
 	-I${top_srcdir}/libnm-util \
 	-I${top_builddir}/libnm-util \
 	-I$(top_srcdir)/src/dhcp-manager \
-	$(GLIB_CFLAGS)
+	-I$(top_srcdir)/src \
+	-I$(top_srcdir)/src/platform \
+	-DG_LOG_DOMAIN=\""NetworkManager"\" \
+	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+	$(GLIB_CFLAGS) \
+	-DTESTDIR="\"$(abs_srcdir)\""
 
 noinst_PROGRAMS = test-dhcp-dhclient
 
@@ -15,22 +18,16 @@ noinst_PROGRAMS = test-dhcp-dhclient
 test_dhcp_dhclient_SOURCES = \
 	test-dhcp-dhclient.c
 
-test_dhcp_dhclient_CPPFLAGS = \
-	$(AM_CPPFLAGS) \
-	-DTESTDIR="\"$(abs_srcdir)\""
-
 test_dhcp_dhclient_LDADD = \
-	-ldl \
-	$(top_builddir)/src/dhcp-manager/libdhcp-dhclient.la \
-	$(top_builddir)/libnm-util/libnm-util.la \
-	$(GLIB_LIBS)
-
-check-local: test-dhcp-dhclient
-	$(abs_builddir)/test-dhcp-dhclient
+	$(top_builddir)/src/libNetworkManager.la
 
-endif
+TESTS = test-dhcp-dhclient
 
 EXTRA_DIST = \
 	test-dhclient-duid.leases \
-	test-dhclient-commented-duid.leases
+	test-dhclient-commented-duid.leases \
+	leases/basic.leases \
+	leases/malformed1.leases \
+	leases/malformed2.leases \
+	leases/malformed3.leases
 
diff --git a/src/dhcp-manager/tests/Makefile.in b/src/dhcp-manager/tests/Makefile.in
index afcee2c0..d445838f 100644
--- a/src/dhcp-manager/tests/Makefile.in
+++ b/src/dhcp-manager/tests/Makefile.in
@@ -78,12 +78,14 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-@ENABLE_TESTS_TRUE@noinst_PROGRAMS = test-dhcp-dhclient$(EXEEXT)
+noinst_PROGRAMS = test-dhcp-dhclient$(EXEEXT)
+TESTS = test-dhcp-dhclient$(EXEEXT)
 subdir = src/dhcp-manager/tests
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
+	$(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/gettext.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
@@ -102,13 +104,10 @@ CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 PROGRAMS = $(noinst_PROGRAMS)
-am__test_dhcp_dhclient_SOURCES_DIST = test-dhcp-dhclient.c
-@ENABLE_TESTS_TRUE@am_test_dhcp_dhclient_OBJECTS = test_dhcp_dhclient-test-dhcp-dhclient.$(OBJEXT)
+am_test_dhcp_dhclient_OBJECTS = test-dhcp-dhclient.$(OBJEXT)
 test_dhcp_dhclient_OBJECTS = $(am_test_dhcp_dhclient_OBJECTS)
-am__DEPENDENCIES_1 =
-@ENABLE_TESTS_TRUE@test_dhcp_dhclient_DEPENDENCIES = $(top_builddir)/src/dhcp-manager/libdhcp-dhclient.la \
-@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-util/libnm-util.la \
-@ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1)
+test_dhcp_dhclient_DEPENDENCIES =  \
+	$(top_builddir)/src/libNetworkManager.la
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
@@ -148,7 +147,7 @@ am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
 SOURCES = $(test_dhcp_dhclient_SOURCES)
-DIST_SOURCES = $(am__test_dhcp_dhclient_SOURCES_DIST)
+DIST_SOURCES = $(test_dhcp_dhclient_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -173,6 +172,28 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -199,12 +220,15 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
+DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
 DBUS_LIBS = @DBUS_LIBS@
 DBUS_SYS_DIR = @DBUS_SYS_DIR@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DHCLIENT_PATH = @DHCLIENT_PATH@
 DHCPCD_PATH = @DHCPCD_PATH@
+DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@
 DLLTOOL = @DLLTOOL@
 DNSMASQ_PATH = @DNSMASQ_PATH@
 DSYMUTIL = @DSYMUTIL@
@@ -229,7 +253,6 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
-GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -274,12 +297,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNDP_CFLAGS = @LIBNDP_CFLAGS@
+LIBNDP_LIBS = @LIBNDP_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
 LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTEAMDCTL_CFLAGS = @LIBTEAMDCTL_CFLAGS@
+LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -296,6 +323,8 @@ MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
+NEWT_CFLAGS = @NEWT_CFLAGS@
+NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
@@ -323,11 +352,16 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
 POLKIT_CFLAGS = @POLKIT_CFLAGS@
 POLKIT_LIBS = @POLKIT_LIBS@
 POSUB = @POSUB@
+PPPD_PATH = @PPPD_PATH@
 PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
+PPPOE_PATH = @PPPOE_PATH@
 QT_CFLAGS = @QT_CFLAGS@
 QT_LIBS = @QT_LIBS@
 RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
 SED = @SED@
+SELINUX_CFLAGS = @SELINUX_CFLAGS@
+SELINUX_LIBS = @SELINUX_LIBS@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
@@ -342,6 +376,7 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VALGRIND_RULES = @VALGRIND_RULES@
 VAPIGEN = @VAPIGEN@
 VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
 VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
@@ -404,6 +439,7 @@ psdir = @psdir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
+subdirs = @subdirs@
 sysconfdir = @sysconfdir@
 systemdsystemunitdir = @systemdsystemunitdir@
 target_alias = @target_alias@
@@ -414,32 +450,35 @@ with_dhclient = @with_dhclient@
 with_dhcpcd = @with_dhcpcd@
 with_netconfig = @with_netconfig@
 with_resolvconf = @with_resolvconf@
-@ENABLE_TESTS_TRUE@AM_CPPFLAGS = \
-@ENABLE_TESTS_TRUE@	-I$(top_srcdir)/include \
-@ENABLE_TESTS_TRUE@	-I$(top_builddir)/include \
-@ENABLE_TESTS_TRUE@	-I${top_srcdir}/libnm-util \
-@ENABLE_TESTS_TRUE@	-I${top_builddir}/libnm-util \
-@ENABLE_TESTS_TRUE@	-I$(top_srcdir)/src/dhcp-manager \
-@ENABLE_TESTS_TRUE@	$(GLIB_CFLAGS)
+with_valgrind = @with_valgrind@
+AM_CPPFLAGS = \
+	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
+	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
+	-I$(top_srcdir)/src/dhcp-manager \
+	-I$(top_srcdir)/src \
+	-I$(top_srcdir)/src/platform \
+	-DG_LOG_DOMAIN=\""NetworkManager"\" \
+	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+	$(GLIB_CFLAGS) \
+	-DTESTDIR="\"$(abs_srcdir)\""
 
 
 ####### policy /etc/hosts test #######
-@ENABLE_TESTS_TRUE@test_dhcp_dhclient_SOURCES = \
-@ENABLE_TESTS_TRUE@	test-dhcp-dhclient.c
-
-@ENABLE_TESTS_TRUE@test_dhcp_dhclient_CPPFLAGS = \
-@ENABLE_TESTS_TRUE@	$(AM_CPPFLAGS) \
-@ENABLE_TESTS_TRUE@	-DTESTDIR="\"$(abs_srcdir)\""
+test_dhcp_dhclient_SOURCES = \
+	test-dhcp-dhclient.c
 
-@ENABLE_TESTS_TRUE@test_dhcp_dhclient_LDADD = \
-@ENABLE_TESTS_TRUE@	-ldl \
-@ENABLE_TESTS_TRUE@	$(top_builddir)/src/dhcp-manager/libdhcp-dhclient.la \
-@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-util/libnm-util.la \
-@ENABLE_TESTS_TRUE@	$(GLIB_LIBS)
+test_dhcp_dhclient_LDADD = \
+	$(top_builddir)/src/libNetworkManager.la
 
 EXTRA_DIST = \
 	test-dhclient-duid.leases \
-	test-dhclient-commented-duid.leases
+	test-dhclient-commented-duid.leases \
+	leases/basic.leases \
+	leases/malformed1.leases \
+	leases/malformed2.leases \
+	leases/malformed3.leases
 
 all: all-am
 
@@ -495,7 +534,7 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dhcp_dhclient-test-dhcp-dhclient.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dhcp-dhclient.Po@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -518,20 +557,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
-test_dhcp_dhclient-test-dhcp-dhclient.o: test-dhcp-dhclient.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_dhcp_dhclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_dhcp_dhclient-test-dhcp-dhclient.o -MD -MP -MF $(DEPDIR)/test_dhcp_dhclient-test-dhcp-dhclient.Tpo -c -o test_dhcp_dhclient-test-dhcp-dhclient.o `test -f 'test-dhcp-dhclient.c' || echo '$(srcdir)/'`test-dhcp-dhclient.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/test_dhcp_dhclient-test-dhcp-dhclient.Tpo $(DEPDIR)/test_dhcp_dhclient-test-dhcp-dhclient.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='test-dhcp-dhclient.c' object='test_dhcp_dhclient-test-dhcp-dhclient.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_dhcp_dhclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_dhcp_dhclient-test-dhcp-dhclient.o `test -f 'test-dhcp-dhclient.c' || echo '$(srcdir)/'`test-dhcp-dhclient.c
-
-test_dhcp_dhclient-test-dhcp-dhclient.obj: test-dhcp-dhclient.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_dhcp_dhclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_dhcp_dhclient-test-dhcp-dhclient.obj -MD -MP -MF $(DEPDIR)/test_dhcp_dhclient-test-dhcp-dhclient.Tpo -c -o test_dhcp_dhclient-test-dhcp-dhclient.obj `if test -f 'test-dhcp-dhclient.c'; then $(CYGPATH_W) 'test-dhcp-dhclient.c'; else $(CYGPATH_W) '$(srcdir)/test-dhcp-dhclient.c'; fi`
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/test_dhcp_dhclient-test-dhcp-dhclient.Tpo $(DEPDIR)/test_dhcp_dhclient-test-dhcp-dhclient.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='test-dhcp-dhclient.c' object='test_dhcp_dhclient-test-dhcp-dhclient.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_dhcp_dhclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_dhcp_dhclient-test-dhcp-dhclient.obj `if test -f 'test-dhcp-dhclient.c'; then $(CYGPATH_W) 'test-dhcp-dhclient.c'; else $(CYGPATH_W) '$(srcdir)/test-dhcp-dhclient.c'; fi`
-
 mostlyclean-libtool:
 	-rm -f *.lo
 
@@ -590,6 +615,99 @@ cscopelist-am: $(am__tagged_files)
 distclean-tags:
 	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list=' $(TESTS) '; \
+	$(am__tty_colors); \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *[\ \	]$$tst[\ \	]*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		col=$$red; res=XPASS; \
+	      ;; \
+	      *) \
+		col=$$grn; res=PASS; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *[\ \	]$$tst[\ \	]*) \
+		xfail=`expr $$xfail + 1`; \
+		col=$$lgn; res=XFAIL; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		col=$$red; res=FAIL; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      col=$$blu; res=SKIP; \
+	    fi; \
+	    echo "$${col}$$res$${std}: $$tst"; \
+	  done; \
+	  if test "$$all" -eq 1; then \
+	    tests="test"; \
+	    All=""; \
+	  else \
+	    tests="tests"; \
+	    All="All "; \
+	  fi; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="$$All$$all $$tests passed"; \
+	    else \
+	      if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+	      banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all $$tests failed"; \
+	    else \
+	      if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+	      banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    if test "$$skip" -eq 1; then \
+	      skipped="($$skip test was not run)"; \
+	    else \
+	      skipped="($$skip tests were not run)"; \
+	    fi; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  if test "$$failed" -eq 0; then \
+	    col="$$grn"; \
+	  else \
+	    col="$$red"; \
+	  fi; \
+	  echo "$${col}$$dashes$${std}"; \
+	  echo "$${col}$$banner$${std}"; \
+	  test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+	  test -z "$$report" || echo "$${col}$$report$${std}"; \
+	  echo "$${col}$$dashes$${std}"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
 distdir: $(DISTFILES)
 	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
 	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
@@ -620,9 +738,8 @@ distdir: $(DISTFILES)
 	    || exit 1; \
 	  fi; \
 	done
-@ENABLE_TESTS_FALSE@check-local:
 check-am: all-am
-	$(MAKE) $(AM_MAKEFLAGS) check-local
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
 check: check-am
 all-am: Makefile $(PROGRAMS)
 installdirs:
@@ -729,7 +846,7 @@ uninstall-am:
 
 .MAKE: check-am install-am install-strip
 
-.PHONY: CTAGS GTAGS TAGS all all-am check check-am check-local clean \
+.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
 	clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \
 	ctags ctags-am distclean distclean-compile distclean-generic \
 	distclean-libtool distclean-tags distdir dvi dvi-am html \
@@ -744,9 +861,6 @@ uninstall-am:
 	tags tags-am uninstall uninstall-am
 
 
-@ENABLE_TESTS_TRUE@check-local: test-dhcp-dhclient
-@ENABLE_TESTS_TRUE@	$(abs_builddir)/test-dhcp-dhclient
-
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/src/dhcp-manager/tests/leases/basic.leases b/src/dhcp-manager/tests/leases/basic.leases
new file mode 100644
index 00000000..703d9247
--- /dev/null
+++ b/src/dhcp-manager/tests/leases/basic.leases
@@ -0,0 +1,31 @@
+lease {
+  interface "wlan0";
+  fixed-address 192.168.1.180;
+  option subnet-mask 255.255.255.0;
+  option routers 192.168.1.1;
+  option dhcp-lease-time 600;
+  option dhcp-message-type 5;
+  option domain-name-servers 192.168.1.1;
+  option dhcp-server-identifier 192.168.1.1;
+  option broadcast-address 192.168.1.255;
+  renew 5 2013/11/01 19:56:15;
+  rebind 5 2013/11/01 20:00:44;
+  expire 5 2013/11/01 20:01:59;
+}
+lease {
+  interface "wlan0";
+  fixed-address 10.77.52.141;
+  option subnet-mask 255.0.0.0;
+  option dhcp-lease-time 1200;
+  option routers 10.77.52.254;
+  option dhcp-message-type 5;
+  option dhcp-server-identifier 10.77.52.254;
+  option domain-name-servers 8.8.8.8,8.8.4.4;
+  option dhcp-renewal-time 600;
+  option dhcp-rebinding-time 1050;
+  option domain-name "morriesguest.local";
+  renew 5 2013/11/01 20:01:08;
+  rebind 5 2013/11/01 20:05:00;
+  expire 5 2013/11/01 20:06:15;
+}
+
diff --git a/src/dhcp-manager/tests/leases/malformed1.leases b/src/dhcp-manager/tests/leases/malformed1.leases
new file mode 100644
index 00000000..401d982a
--- /dev/null
+++ b/src/dhcp-manager/tests/leases/malformed1.leases
@@ -0,0 +1,15 @@
+# missing fixed-address option
+lease {
+  interface "wlan0";
+  option subnet-mask 255.255.255.0;
+  option routers 192.168.1.1;
+  option dhcp-lease-time 600;
+  option dhcp-message-type 5;
+  option domain-name-servers 192.168.1.1;
+  option dhcp-server-identifier 192.168.1.1;
+  option broadcast-address 192.168.1.255;
+  renew 5 2013/11/01 19:56:15;
+  rebind 5 2013/11/01 20:00:44;
+  expire 5 2013/11/01 20:01:59;
+}
+
diff --git a/src/dhcp-manager/tests/leases/malformed2.leases b/src/dhcp-manager/tests/leases/malformed2.leases
new file mode 100644
index 00000000..adf5f6de
--- /dev/null
+++ b/src/dhcp-manager/tests/leases/malformed2.leases
@@ -0,0 +1,15 @@
+# missing routers option
+lease {
+  interface "wlan0";
+  fixed-address 192.168.1.180;
+  option subnet-mask 255.255.255.0;
+  option dhcp-lease-time 600;
+  option dhcp-message-type 5;
+  option domain-name-servers 192.168.1.1;
+  option dhcp-server-identifier 192.168.1.1;
+  option broadcast-address 192.168.1.255;
+  renew 5 2013/11/01 19:56:15;
+  rebind 5 2013/11/01 20:00:44;
+  expire 5 2013/11/01 20:01:59;
+}
+
diff --git a/src/dhcp-manager/tests/leases/malformed3.leases b/src/dhcp-manager/tests/leases/malformed3.leases
new file mode 100644
index 00000000..a2afc8b6
--- /dev/null
+++ b/src/dhcp-manager/tests/leases/malformed3.leases
@@ -0,0 +1,15 @@
+# missing expire time
+lease {
+  interface "wlan0";
+  fixed-address 192.168.1.180;
+  option subnet-mask 255.255.255.0;
+  option routers 192.168.1.1;
+  option dhcp-lease-time 600;
+  option dhcp-message-type 5;
+  option domain-name-servers 192.168.1.1;
+  option dhcp-server-identifier 192.168.1.1;
+  option broadcast-address 192.168.1.255;
+  renew 5 2013/11/01 19:56:15;
+  rebind 5 2013/11/01 20:00:44;
+}
+
diff --git a/src/dhcp-manager/tests/test-dhcp-dhclient.c b/src/dhcp-manager/tests/test-dhcp-dhclient.c
index 3f34c6e0..1ab182a7 100644
--- a/src/dhcp-manager/tests/test-dhcp-dhclient.c
+++ b/src/dhcp-manager/tests/test-dhcp-dhclient.c
@@ -24,6 +24,7 @@
 
 #include "nm-dhcp-dhclient-utils.h"
 #include "nm-utils.h"
+#include "nm-ip4-config.h"
 
 #define DEBUG 0
 
@@ -33,18 +34,13 @@ test_config (const char *orig,
              const char *hostname,
              const char *dhcp_client_id,
              const char *iface,
-             guint8 *anycast_addr)
+             GByteArray *anycast_addr)
 {
-	NMSettingIP4Config *s_ip4;
 	char *new;
 
-	s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
-	g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, dhcp_client_id, NULL);
-
 	new = nm_dhcp_dhclient_create_config (iface,
 	                                      FALSE,
-	                                      s_ip4,
-	                                      NULL,
+	                                      dhcp_client_id,
 	                                      anycast_addr,
 	                                      hostname,
 	                                      "/path/to/dhclient.conf",
@@ -127,6 +123,62 @@ test_override_client_id (void)
 
 /*******************************************/
 
+static const char *quote_client_id_expected = \
+	"# Created by NetworkManager\n"
+	"\n"
+	"send dhcp-client-identifier \"1234\"; # added by NetworkManager\n"
+	"\n"
+	"option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n"
+	"option ms-classless-static-routes code 249 = array of unsigned integer 8;\n"
+	"option wpad code 252 = string;\n"
+	"\n"
+	"also request rfc3442-classless-static-routes;\n"
+	"also request ms-classless-static-routes;\n"
+	"also request static-routes;\n"
+	"also request wpad;\n"
+	"also request ntp-servers;\n"
+	"\n";
+
+static void
+test_quote_client_id (void)
+{
+	test_config (NULL, quote_client_id_expected,
+	             NULL,
+	             "1234",
+	             "eth0",
+	             NULL);
+}
+
+/*******************************************/
+
+static const char *ascii_client_id_expected = \
+	"# Created by NetworkManager\n"
+	"\n"
+	"send dhcp-client-identifier \"qb:cd:ef:12:34:56\"; # added by NetworkManager\n"
+	"\n"
+	"option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n"
+	"option ms-classless-static-routes code 249 = array of unsigned integer 8;\n"
+	"option wpad code 252 = string;\n"
+	"\n"
+	"also request rfc3442-classless-static-routes;\n"
+	"also request ms-classless-static-routes;\n"
+	"also request static-routes;\n"
+	"also request wpad;\n"
+	"also request ntp-servers;\n"
+	"\n";
+
+static void
+test_ascii_client_id (void)
+{
+	test_config (NULL, ascii_client_id_expected,
+	             NULL,
+	             "qb:cd:ef:12:34:56",
+	             "eth0",
+	             NULL);
+}
+
+/*******************************************/
+
 static const char *override_hostname_orig = \
 	"send host-name \"foobar\";\n";
 
@@ -398,37 +450,164 @@ test_write_existing_commented_duid (void)
 
 /*******************************************/
 
-#if GLIB_CHECK_VERSION(2,25,12)
-typedef GTestFixtureFunc TCFunc;
-#else
-typedef void (*TCFunc)(void);
-#endif
+static void
+test_read_lease_ip4_config_basic (void)
+{
+	GError *error = NULL;
+	char *contents = NULL;
+	gboolean success;
+	const char *path = TESTDIR "/leases/basic.leases";
+	GSList *leases;
+	GDateTime *now;
+	NMIP4Config *config;
+	const NMPlatformIP4Address *addr;
+	guint32 expected_addr;
+
+	success = g_file_get_contents (path, &contents, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (success);
 
-#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL)
+	/* Date from before the least expiration */
+	now = g_date_time_new_utc (2013, 11, 1, 19, 55, 32);
+	leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", contents, FALSE, now);
+	g_assert_cmpint (g_slist_length (leases), ==, 2);
+
+	/* IP4Config #1 */
+	config = g_slist_nth_data (leases, 0);
+	g_assert (NM_IS_IP4_CONFIG (config));
+
+	/* Address */
+	g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1);
+	g_assert (inet_aton ("192.168.1.180", (struct in_addr *) &expected_addr));
+	addr = nm_ip4_config_get_address (config, 0);
+	g_assert_cmpint (addr->address, ==, expected_addr);
+	g_assert_cmpint (addr->plen, ==, 24);
+
+	/* Gateway */
+	g_assert (inet_aton ("192.168.1.1", (struct in_addr *) &expected_addr));
+	g_assert_cmpint (nm_ip4_config_get_gateway (config), ==, expected_addr);
+
+	/* DNS */
+	g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 1);
+	g_assert (inet_aton ("192.168.1.1", (struct in_addr *) &expected_addr));
+	g_assert_cmpint (nm_ip4_config_get_nameserver (config, 0), ==, expected_addr);
+
+	g_assert_cmpint (nm_ip4_config_get_num_domains (config), ==, 0);
+
+	/* IP4Config #2 */
+	config = g_slist_nth_data (leases, 1);
+	g_assert (NM_IS_IP4_CONFIG (config));
+
+	/* Address */
+	g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1);
+	g_assert (inet_aton ("10.77.52.141", (struct in_addr *) &expected_addr));
+	addr = nm_ip4_config_get_address (config, 0);
+	g_assert_cmpint (addr->address, ==, expected_addr);
+	g_assert_cmpint (addr->plen, ==, 8);
+
+	/* Gateway */
+	g_assert (inet_aton ("10.77.52.254", (struct in_addr *) &expected_addr));
+	g_assert_cmpint (nm_ip4_config_get_gateway (config), ==, expected_addr);
+
+	/* DNS */
+	g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 2);
+	g_assert (inet_aton ("8.8.8.8", (struct in_addr *) &expected_addr));
+	g_assert_cmpint (nm_ip4_config_get_nameserver (config, 0), ==, expected_addr);
+	g_assert (inet_aton ("8.8.4.4", (struct in_addr *) &expected_addr));
+	g_assert_cmpint (nm_ip4_config_get_nameserver (config, 1), ==, expected_addr);
+
+	/* Domains */
+	g_assert_cmpint (nm_ip4_config_get_num_domains (config), ==, 1);
+	g_assert_cmpstr (nm_ip4_config_get_domain (config, 0), ==, "morriesguest.local");
+
+	g_slist_free_full (leases, g_object_unref);
+	g_date_time_unref (now);
+	g_free (contents);
+}
 
-int main (int argc, char **argv)
+static void
+test_read_lease_ip4_config_expired (void)
 {
-	GTestSuite *suite;
+	GError *error = NULL;
+	char *contents = NULL;
+	gboolean success;
+	const char *path = TESTDIR "/leases/basic.leases";
+	GSList *leases;
+	GDateTime *now;
 
-	g_test_init (&argc, &argv, NULL);
+	success = g_file_get_contents (path, &contents, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (success);
 
-	g_type_init ();
+	/* Date from *after* the lease expiration */
+	now = g_date_time_new_utc (2013, 12, 1, 19, 55, 32);
+	leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", contents, FALSE, now);
+	g_assert (leases == NULL);
+
+	g_date_time_unref (now);
+	g_free (contents);
+}
+
+static void
+test_read_lease_ip4_config_expect_failure (gconstpointer user_data)
+{
+	GError *error = NULL;
+	char *contents = NULL;
+	gboolean success;
+	GSList *leases;
+	GDateTime *now;
+
+	success = g_file_get_contents ((const char *) user_data, &contents, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	/* Date from before the least expiration */
+	now = g_date_time_new_utc (2013, 11, 1, 1, 1, 1);
+	leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", contents, FALSE, now);
+	g_assert (leases == NULL);
 
-	suite = g_test_get_root ();
+	g_date_time_unref (now);
+	g_free (contents);
+}
 
-	g_test_suite_add (suite, TESTCASE (test_orig_missing, NULL));
-	g_test_suite_add (suite, TESTCASE (test_override_client_id, NULL));
-	g_test_suite_add (suite, TESTCASE (test_override_hostname, NULL));
-	g_test_suite_add (suite, TESTCASE (test_existing_alsoreq, NULL));
-	g_test_suite_add (suite, TESTCASE (test_existing_multiline_alsoreq, NULL));
-	g_test_suite_add (suite, TESTCASE (test_duids, NULL));
+/*******************************************/
 
-	g_test_suite_add (suite, TESTCASE (test_read_duid_from_leasefile, NULL));
-	g_test_suite_add (suite, TESTCASE (test_read_commented_duid_from_leasefile, NULL));
+int
+main (int argc, char **argv)
+{
+	g_test_init (&argc, &argv, NULL);
+
+#if !GLIB_CHECK_VERSION (2, 35, 0)
+	g_type_init ();
+#endif
 
-	g_test_suite_add (suite, TESTCASE (test_write_duid, NULL));
-	g_test_suite_add (suite, TESTCASE (test_write_existing_duid, NULL));
-	g_test_suite_add (suite, TESTCASE (test_write_existing_commented_duid, NULL));
+	g_test_add_func ("/dhcp/dhclient/orig_missing", test_orig_missing);
+	g_test_add_func ("/dhcp/dhclient/override_client_id", test_override_client_id);
+	g_test_add_func ("/dhcp/dhclient/quote_client_id", test_quote_client_id);
+	g_test_add_func ("/dhcp/dhclient/ascii_client_id", test_ascii_client_id);
+	g_test_add_func ("/dhcp/dhclient/override_hostname", test_override_hostname);
+	g_test_add_func ("/dhcp/dhclient/existing_alsoreq", test_existing_alsoreq);
+	g_test_add_func ("/dhcp/dhclient/existing_multiline_alsoreq", test_existing_multiline_alsoreq);
+	g_test_add_func ("/dhcp/dhclient/duids", test_duids);
+
+	g_test_add_func ("/dhcp/dhclient/read_duid_from_leasefile", test_read_duid_from_leasefile);
+	g_test_add_func ("/dhcp/dhclient/read_commented_duid_from_leasefile", test_read_commented_duid_from_leasefile);
+
+	g_test_add_func ("/dhcp/dhclient/write_duid", test_write_duid);
+	g_test_add_func ("/dhcp/dhclient/write_existing_duid", test_write_existing_duid);
+	g_test_add_func ("/dhcp/dhclient/write_existing_commented_duid", test_write_existing_commented_duid);
+
+	g_test_add_func ("/dhcp/dhclient/leases/ip4-config/basic", test_read_lease_ip4_config_basic);
+	g_test_add_func ("/dhcp/dhclient/leases/ip4-config/expired", test_read_lease_ip4_config_expired);
+	g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-address",
+	                      TESTDIR "/leases/malformed1.leases",
+	                      test_read_lease_ip4_config_expect_failure);
+	g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-gateway",
+	                      TESTDIR "/leases/malformed2.leases",
+	                      test_read_lease_ip4_config_expect_failure);
+	g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-expire",
+	                      TESTDIR "/leases/malformed3.leases",
+	                      test_read_lease_ip4_config_expect_failure);
 
 	return g_test_run ();
 }