about summary refs log tree commit diff
path: root/src/bluez-manager
diff options
context:
space:
mode:
authorSjoerd Simons <sjoerd@luon.net>2013-10-25 21:20:58 +0200
committerSjoerd Simons <sjoerd@luon.net>2013-10-25 21:20:58 +0200
commita4256940da049f91bbbea5e53e469a59ea9c10f7 (patch)
tree2211c102aea3a33f34f960f48c8b8a55daccd97b /src/bluez-manager
parent8d275584fc94f398f0a7c990dcd057533d9a5856 (diff)
Imported Upstream version 0.9.8.8 upstream/0.9.8.8
Diffstat (limited to 'src/bluez-manager')
-rw-r--r--src/bluez-manager/Makefile.am17
-rw-r--r--src/bluez-manager/Makefile.in279
-rw-r--r--src/bluez-manager/nm-bluez-common.h17
-rw-r--r--src/bluez-manager/nm-bluez-device.c728
-rw-r--r--src/bluez-manager/nm-bluez-device.h19
-rw-r--r--src/bluez-manager/nm-bluez-manager.c330
-rw-r--r--src/bluez-manager/nm-bluez-manager.h1
-rw-r--r--src/bluez-manager/nm-bluez4-adapter.c (renamed from src/bluez-manager/nm-bluez-adapter.c)2
-rw-r--r--src/bluez-manager/nm-bluez4-adapter.h (renamed from src/bluez-manager/nm-bluez-adapter.h)0
-rw-r--r--src/bluez-manager/nm-bluez4-manager.c386
10 files changed, 1483 insertions, 296 deletions
diff --git a/src/bluez-manager/Makefile.am b/src/bluez-manager/Makefile.am
index 7e7ed9a0..aee27217 100644
--- a/src/bluez-manager/Makefile.am
+++ b/src/bluez-manager/Makefile.am
@@ -12,13 +12,20 @@ INCLUDES = \
 noinst_LTLIBRARIES = libbluez-manager.la
 
 libbluez_manager_la_SOURCES = \
-	nm-bluez-manager.c \
-	nm-bluez-manager.h \
-	nm-bluez-adapter.c \
-	nm-bluez-adapter.h \
+	nm-bluez-common.h \
 	nm-bluez-device.c \
 	nm-bluez-device.h \
-	nm-bluez-common.h
+	nm-bluez-manager.h
+
+if WITH_BLUEZ4
+libbluez_manager_la_SOURCES += \
+	nm-bluez4-adapter.h \
+	nm-bluez4-adapter.c \
+	nm-bluez4-manager.c
+else
+libbluez_manager_la_SOURCES += \
+	nm-bluez-manager.c
+endif
 
 libbluez_manager_la_CPPFLAGS = \
 	$(DBUS_CFLAGS) \
diff --git a/src/bluez-manager/Makefile.in b/src/bluez-manager/Makefile.in
index 5606d11c..f4dd166f 100644
--- a/src/bluez-manager/Makefile.in
+++ b/src/bluez-manager/Makefile.in
@@ -1,9 +1,8 @@
-# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
-# Foundation, Inc.
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
@@ -16,23 +15,51 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__make_dryrun = \
-  { \
-    am__dry=no; \
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
     case $$MAKEFLAGS in \
       *\\[\ \	]*) \
-        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
-          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
-      *) \
-        for am__flg in $$MAKEFLAGS; do \
-          case $$am__flg in \
-            *=*|--*) ;; \
-            *n*) am__dry=yes; break;; \
-          esac; \
-        done;; \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
     esac; \
-    test $$am__dry = yes; \
-  }
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
 pkgdatadir = $(datadir)/@PACKAGE@
 pkgincludedir = $(includedir)/@PACKAGE@
 pkglibdir = $(libdir)/@PACKAGE@
@@ -51,8 +78,17 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
+@WITH_BLUEZ4_TRUE@am__append_1 = \
+@WITH_BLUEZ4_TRUE@	nm-bluez4-adapter.h \
+@WITH_BLUEZ4_TRUE@	nm-bluez4-adapter.c \
+@WITH_BLUEZ4_TRUE@	nm-bluez4-manager.c
+
+@WITH_BLUEZ4_FALSE@am__append_2 = \
+@WITH_BLUEZ4_FALSE@	nm-bluez-manager.c
+
 subdir = src/bluez-manager
-DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+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 \
 	$(top_srcdir)/m4/gettext.m4 \
@@ -78,14 +114,35 @@ libbluez_manager_la_DEPENDENCIES =  \
 	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am__libbluez_manager_la_SOURCES_DIST = nm-bluez-common.h \
+	nm-bluez-device.c nm-bluez-device.h nm-bluez-manager.h \
+	nm-bluez4-adapter.h nm-bluez4-adapter.c nm-bluez4-manager.c \
+	nm-bluez-manager.c
+@WITH_BLUEZ4_TRUE@am__objects_1 =  \
+@WITH_BLUEZ4_TRUE@	libbluez_manager_la-nm-bluez4-adapter.lo \
+@WITH_BLUEZ4_TRUE@	libbluez_manager_la-nm-bluez4-manager.lo
+@WITH_BLUEZ4_FALSE@am__objects_2 =  \
+@WITH_BLUEZ4_FALSE@	libbluez_manager_la-nm-bluez-manager.lo
 am_libbluez_manager_la_OBJECTS =  \
-	libbluez_manager_la-nm-bluez-manager.lo \
-	libbluez_manager_la-nm-bluez-adapter.lo \
-	libbluez_manager_la-nm-bluez-device.lo
+	libbluez_manager_la-nm-bluez-device.lo $(am__objects_1) \
+	$(am__objects_2)
 libbluez_manager_la_OBJECTS = $(am_libbluez_manager_la_OBJECTS)
 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 = 
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
 am__depfiles_maybe = depfiles
@@ -98,27 +155,40 @@ LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(AM_CFLAGS) $(CFLAGS)
 AM_V_CC = $(am__v_CC_@AM_V@)
 am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
-am__v_CC_0 = @echo "  CC    " $@;
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
 CCLD = $(CC)
 LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
 	$(AM_LDFLAGS) $(LDFLAGS) -o $@
 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_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo "  GEN   " $@;
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
 SOURCES = $(libbluez_manager_la_SOURCES)
-DIST_SOURCES = $(libbluez_manager_la_SOURCES)
+DIST_SOURCES = $(am__libbluez_manager_la_SOURCES_DIST)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
+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
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -263,7 +333,6 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
 PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
-PKGCONFIG_PATH = @PKGCONFIG_PATH@
 PKG_CONFIG = @PKG_CONFIG@
 PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
 PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
@@ -278,6 +347,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_200_CFLAGS = @SYSTEMD_200_CFLAGS@
+SYSTEMD_200_LIBS = @SYSTEMD_200_LIBS@
 SYSTEMD_INHIBIT_CFLAGS = @SYSTEMD_INHIBIT_CFLAGS@
 SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@
 SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@
@@ -371,15 +442,9 @@ INCLUDES = \
 	-I${top_srcdir}/src/logging
 
 noinst_LTLIBRARIES = libbluez-manager.la
-libbluez_manager_la_SOURCES = \
-	nm-bluez-manager.c \
-	nm-bluez-manager.h \
-	nm-bluez-adapter.c \
-	nm-bluez-adapter.h \
-	nm-bluez-device.c \
-	nm-bluez-device.h \
-	nm-bluez-common.h
-
+libbluez_manager_la_SOURCES = nm-bluez-common.h nm-bluez-device.c \
+	nm-bluez-device.h nm-bluez-manager.h $(am__append_1) \
+	$(am__append_2)
 libbluez_manager_la_CPPFLAGS = \
 	$(DBUS_CFLAGS) \
 	$(GLIB_CFLAGS) \
@@ -434,12 +499,15 @@ $(am__aclocal_m4_deps):
 
 clean-noinstLTLIBRARIES:
 	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
-	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
-	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
-	  test "$$dir" != "$$p" || dir=.; \
-	  echo "rm -f \"$${dir}/so_locations\""; \
-	  rm -f "$${dir}/so_locations"; \
-	done
+	@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}; \
+	}
+
 libbluez-manager.la: $(libbluez_manager_la_OBJECTS) $(libbluez_manager_la_DEPENDENCIES) $(EXTRA_libbluez_manager_la_DEPENDENCIES) 
 	$(AM_V_CCLD)$(LINK)  $(libbluez_manager_la_OBJECTS) $(libbluez_manager_la_LIBADD) $(LIBS)
 
@@ -449,9 +517,10 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libbluez_manager_la-nm-bluez-adapter.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libbluez_manager_la-nm-bluez-device.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libbluez_manager_la-nm-bluez-manager.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libbluez_manager_la-nm-bluez4-adapter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libbluez_manager_la-nm-bluez4-manager.Plo@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -474,20 +543,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
-libbluez_manager_la-nm-bluez-manager.lo: nm-bluez-manager.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libbluez_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libbluez_manager_la-nm-bluez-manager.lo -MD -MP -MF $(DEPDIR)/libbluez_manager_la-nm-bluez-manager.Tpo -c -o libbluez_manager_la-nm-bluez-manager.lo `test -f 'nm-bluez-manager.c' || echo '$(srcdir)/'`nm-bluez-manager.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libbluez_manager_la-nm-bluez-manager.Tpo $(DEPDIR)/libbluez_manager_la-nm-bluez-manager.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-bluez-manager.c' object='libbluez_manager_la-nm-bluez-manager.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) $(libbluez_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libbluez_manager_la-nm-bluez-manager.lo `test -f 'nm-bluez-manager.c' || echo '$(srcdir)/'`nm-bluez-manager.c
-
-libbluez_manager_la-nm-bluez-adapter.lo: nm-bluez-adapter.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libbluez_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libbluez_manager_la-nm-bluez-adapter.lo -MD -MP -MF $(DEPDIR)/libbluez_manager_la-nm-bluez-adapter.Tpo -c -o libbluez_manager_la-nm-bluez-adapter.lo `test -f 'nm-bluez-adapter.c' || echo '$(srcdir)/'`nm-bluez-adapter.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libbluez_manager_la-nm-bluez-adapter.Tpo $(DEPDIR)/libbluez_manager_la-nm-bluez-adapter.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-bluez-adapter.c' object='libbluez_manager_la-nm-bluez-adapter.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) $(libbluez_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libbluez_manager_la-nm-bluez-adapter.lo `test -f 'nm-bluez-adapter.c' || echo '$(srcdir)/'`nm-bluez-adapter.c
-
 libbluez_manager_la-nm-bluez-device.lo: nm-bluez-device.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libbluez_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libbluez_manager_la-nm-bluez-device.lo -MD -MP -MF $(DEPDIR)/libbluez_manager_la-nm-bluez-device.Tpo -c -o libbluez_manager_la-nm-bluez-device.lo `test -f 'nm-bluez-device.c' || echo '$(srcdir)/'`nm-bluez-device.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libbluez_manager_la-nm-bluez-device.Tpo $(DEPDIR)/libbluez_manager_la-nm-bluez-device.Plo
@@ -495,32 +550,42 @@ libbluez_manager_la-nm-bluez-device.lo: nm-bluez-device.c
 @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) $(libbluez_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libbluez_manager_la-nm-bluez-device.lo `test -f 'nm-bluez-device.c' || echo '$(srcdir)/'`nm-bluez-device.c
 
+libbluez_manager_la-nm-bluez4-adapter.lo: nm-bluez4-adapter.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libbluez_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libbluez_manager_la-nm-bluez4-adapter.lo -MD -MP -MF $(DEPDIR)/libbluez_manager_la-nm-bluez4-adapter.Tpo -c -o libbluez_manager_la-nm-bluez4-adapter.lo `test -f 'nm-bluez4-adapter.c' || echo '$(srcdir)/'`nm-bluez4-adapter.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libbluez_manager_la-nm-bluez4-adapter.Tpo $(DEPDIR)/libbluez_manager_la-nm-bluez4-adapter.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-bluez4-adapter.c' object='libbluez_manager_la-nm-bluez4-adapter.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) $(libbluez_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libbluez_manager_la-nm-bluez4-adapter.lo `test -f 'nm-bluez4-adapter.c' || echo '$(srcdir)/'`nm-bluez4-adapter.c
+
+libbluez_manager_la-nm-bluez4-manager.lo: nm-bluez4-manager.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libbluez_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libbluez_manager_la-nm-bluez4-manager.lo -MD -MP -MF $(DEPDIR)/libbluez_manager_la-nm-bluez4-manager.Tpo -c -o libbluez_manager_la-nm-bluez4-manager.lo `test -f 'nm-bluez4-manager.c' || echo '$(srcdir)/'`nm-bluez4-manager.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libbluez_manager_la-nm-bluez4-manager.Tpo $(DEPDIR)/libbluez_manager_la-nm-bluez4-manager.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-bluez4-manager.c' object='libbluez_manager_la-nm-bluez4-manager.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) $(libbluez_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libbluez_manager_la-nm-bluez4-manager.lo `test -f 'nm-bluez4-manager.c' || echo '$(srcdir)/'`nm-bluez4-manager.c
+
+libbluez_manager_la-nm-bluez-manager.lo: nm-bluez-manager.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libbluez_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libbluez_manager_la-nm-bluez-manager.lo -MD -MP -MF $(DEPDIR)/libbluez_manager_la-nm-bluez-manager.Tpo -c -o libbluez_manager_la-nm-bluez-manager.lo `test -f 'nm-bluez-manager.c' || echo '$(srcdir)/'`nm-bluez-manager.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libbluez_manager_la-nm-bluez-manager.Tpo $(DEPDIR)/libbluez_manager_la-nm-bluez-manager.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-bluez-manager.c' object='libbluez_manager_la-nm-bluez-manager.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) $(libbluez_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libbluez_manager_la-nm-bluez-manager.lo `test -f 'nm-bluez-manager.c' || echo '$(srcdir)/'`nm-bluez-manager.c
+
 mostlyclean-libtool:
 	-rm -f *.lo
 
 clean-libtool:
 	-rm -rf .libs _libs
 
-ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
-	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
-	unique=`for i in $$list; do \
-	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-	  done | \
-	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
-	      END { if (nonempty) { for (i in files) print i; }; }'`; \
-	mkid -fID $$unique
-tags: TAGS
-
-TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
-		$(TAGS_FILES) $(LISP)
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
 	set x; \
 	here=`pwd`; \
-	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
-	unique=`for i in $$list; do \
-	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-	  done | \
-	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
-	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	$(am__define_uniq_tagged_files); \
 	shift; \
 	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
 	  test -n "$$unique" || unique=$$empty_fix; \
@@ -532,15 +597,11 @@ TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
 	      $$unique; \
 	  fi; \
 	fi
-ctags: CTAGS
-CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
-		$(TAGS_FILES) $(LISP)
-	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
-	unique=`for i in $$list; do \
-	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-	  done | \
-	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
-	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
 	test -z "$(CTAGS_ARGS)$$unique" \
 	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
 	     $$unique
@@ -549,6 +610,21 @@ GTAGS:
 	here=`$(am__cd) $(top_builddir) && pwd` \
 	  && $(am__cd) $(top_srcdir) \
 	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
 
 distclean-tags:
 	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
@@ -690,18 +766,19 @@ uninstall-am:
 
 .MAKE: install-am install-strip
 
-.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
-	clean-libtool clean-noinstLTLIBRARIES ctags 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 \
-	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 \
-	maintainer-clean maintainer-clean-generic mostlyclean \
-	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
-	pdf pdf-am ps ps-am tags uninstall uninstall-am
+.PHONY: 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 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 maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
 
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/src/bluez-manager/nm-bluez-common.h b/src/bluez-manager/nm-bluez-common.h
index 61296255..ecc4d709 100644
--- a/src/bluez-manager/nm-bluez-common.h
+++ b/src/bluez-manager/nm-bluez-common.h
@@ -21,14 +21,31 @@
 #ifndef NM_BLUEZ_COMMON_H
 #define NM_BLUEZ_COMMON_H
 
+#include <config.h>
+
+#define BLUETOOTH_CONNECT_DUN "dun"
+#define BLUETOOTH_CONNECT_NAP "nap"
+
 #define BLUEZ_SERVICE           "org.bluez"
 
 #define BLUEZ_MANAGER_PATH      "/"
+#define OBJECT_MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager"
+
+#if ! WITH_BLUEZ4
+
+#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
+#define BLUEZ_DEVICE_INTERFACE  "org.bluez.Device1"
+#define BLUEZ_NETWORK_INTERFACE "org.bluez.Network1"
+
+#else
+
 #define BLUEZ_MANAGER_INTERFACE "org.bluez.Manager"
 #define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter"
 #define BLUEZ_DEVICE_INTERFACE  "org.bluez.Device"
 #define BLUEZ_SERIAL_INTERFACE  "org.bluez.Serial"
 #define BLUEZ_NETWORK_INTERFACE "org.bluez.Network"
 
+#endif /* WITH_BLUEZ */
+
 #endif  /* NM_BLUEZ_COMMON_H */
 
diff --git a/src/bluez-manager/nm-bluez-device.c b/src/bluez-manager/nm-bluez-device.c
index b12a8619..ed5e345d 100644
--- a/src/bluez-manager/nm-bluez-device.c
+++ b/src/bluez-manager/nm-bluez-device.c
@@ -16,9 +16,12 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2009 - 2012 Red Hat, Inc.
+ * Copyright (C) 2013 Intel Corporation.
  */
 
 #include <glib.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
 #include <string.h>
 #include <net/ethernet.h>
 #include <netinet/ether.h>
@@ -26,12 +29,15 @@
 #include "NetworkManager.h"
 #include "nm-setting-bluetooth.h"
 
-#include "nm-dbus-manager.h"
-#include "nm-bluez-device.h"
 #include "nm-bluez-common.h"
+#if WITH_BLUEZ4
+#include "nm-dbus-manager.h"
 #include "nm-dbus-glib-types.h"
+#endif
+#include "nm-bluez-device.h"
 #include "nm-logging.h"
 #include "nm-marshal.h"
+#include "nm-utils.h"
 
 
 G_DEFINE_TYPE (NMBluezDevice, nm_bluez_device, G_TYPE_OBJECT)
@@ -40,18 +46,33 @@ G_DEFINE_TYPE (NMBluezDevice, nm_bluez_device, G_TYPE_OBJECT)
 
 typedef struct {
 	char *path;
-	DBusGProxy *proxy;
+	GDBusConnection *dbus_connection;
+#if ! WITH_BLUEZ4
+	GDBusProxy *proxy5;
+	GDBusProxy *adapter;
+	gboolean adapter_powered;
+#else
+	DBusGProxy *proxy4;
+#endif
+
 	gboolean initialized;
 	gboolean usable;
+	NMBluetoothCapabilities connection_bt_type;
 
 	char *address;
 	guint8 bin_address[ETH_ALEN];
 	char *name;
 	guint32 capabilities;
 	gint rssi;
+	gboolean connected;
+
+	char *bt_iface;
 
 	NMConnectionProvider *provider;
 	GSList *connections;
+
+	NMConnection *pan_connection;
+	gboolean pan_connection_no_autocreate;
 } NMBluezDevicePrivate;
 
 
@@ -63,6 +84,7 @@ enum {
 	PROP_CAPABILITIES,
 	PROP_RSSI,
 	PROP_USABLE,
+	PROP_CONNECTED,
 
 	LAST_PROP
 };
@@ -74,6 +96,12 @@ enum {
 };
 static guint signals[LAST_SIGNAL] = { 0 };
 
+
+static void cp_connection_added (NMConnectionProvider *provider,
+                                 NMConnection *connection, NMBluezDevice *self);
+static gboolean connection_compatible (NMBluezDevice *self, NMConnection *connection);
+
+
 /***********************************************************/
 
 const char *
@@ -132,13 +160,147 @@ nm_bluez_device_get_rssi (NMBluezDevice *self)
 	return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->rssi;
 }
 
+gboolean
+nm_bluez_device_get_connected (NMBluezDevice *self)
+{
+	g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), FALSE);
+
+	return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->connected;
+}
+
+static void
+pan_connection_check_create (NMBluezDevice *self)
+{
+	NMConnection *connection;
+	NMConnection *added;
+	NMSetting *setting;
+	char *uuid, *id;
+	GByteArray *bdaddr_array;
+	GError *error = NULL;
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+
+	g_return_if_fail (priv->capabilities & NM_BT_CAPABILITY_NAP);
+	g_return_if_fail (priv->connections == NULL);
+	g_return_if_fail (priv->name);
+
+	if (priv->pan_connection || priv->pan_connection_no_autocreate) {
+		/* already have a connection or we don't want to create one, nothing to do. */
+		return;
+	}
+
+	if (!nm_connection_provider_has_connections_loaded (priv->provider)) {
+		/* do not try to create any connections until the connection provider is ready. */
+		return;
+	}
+
+	/* Only try once to create a connection. If it does not succeed, we do not try again. Also,
+	 * if the connection gets deleted later, do not create another one for this device. */
+	priv->pan_connection_no_autocreate = TRUE;
+
+	/* create a new connection */
+
+	connection = nm_connection_new ();
+
+	/* Setting: Connection */
+	uuid = nm_utils_uuid_generate ();
+	id = g_strdup_printf (_("%s Network"), priv->name);
+	setting = nm_setting_connection_new ();
+	g_object_set (setting,
+	              NM_SETTING_CONNECTION_ID, id,
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_BLUETOOTH_SETTING_NAME,
+	              NULL);
+	nm_connection_add_setting (connection, setting);
+
+	/* Setting: Bluetooth */
+	bdaddr_array = g_byte_array_sized_new (sizeof (priv->bin_address));
+	g_byte_array_append (bdaddr_array, priv->bin_address, sizeof (priv->bin_address));
+	setting = nm_setting_bluetooth_new ();
+	g_object_set (G_OBJECT (setting),
+	              NM_SETTING_BLUETOOTH_BDADDR, bdaddr_array,
+	              NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU,
+	              NULL);
+	nm_connection_add_setting (connection, setting);
+	g_byte_array_free (bdaddr_array, TRUE);
+
+	/* Setting: IPv4 */
+	setting = nm_setting_ip4_config_new ();
+	g_object_set (G_OBJECT (setting),
+	              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+	              NM_SETTING_IP4_CONFIG_MAY_FAIL, FALSE,
+	              NULL);
+	nm_connection_add_setting (connection, setting);
+
+	/* Setting: IPv6 */
+	setting = nm_setting_ip6_config_new ();
+	g_object_set (G_OBJECT (setting),
+	              NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO,
+	              NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE,
+	              NULL);
+	nm_connection_add_setting (connection, setting);
+
+	/* Adding a new connection raises a signal which eventually calls check_emit_usable (again)
+	 * which then already finds the suitable connection in priv->connections. This is confusing,
+	 * so block the signal. check_emit_usable will succeed after this function call returns. */
+	g_signal_handlers_block_by_func (priv->provider, cp_connection_added, self);
+	added = nm_connection_provider_add_connection (priv->provider, connection, &error);
+	g_signal_handlers_unblock_by_func (priv->provider, cp_connection_added, self);
+
+	if (added) {
+		g_assert (!g_slist_find (priv->connections, added));
+		g_assert (connection_compatible (self, added));
+
+		priv->connections = g_slist_prepend (priv->connections, g_object_ref (added));
+		priv->pan_connection = added;
+		nm_log_dbg (LOGD_SETTINGS, "added new Bluetooth connection for NAP device '%s': '%s' (%s)", priv->path, id, uuid);
+	} else {
+		nm_log_warn (LOGD_SETTINGS, "couldn't add new Bluetooth connection for NAP device '%s': '%s' (%s): %d / %s",
+		             priv->path, id, uuid, error ? error->code : -1,
+		             (error && error->message) ? error->message : "(unknown)");
+		g_clear_error (&error);
+	}
+
+	g_object_unref (connection);
+	g_free (id);
+	g_free (uuid);
+}
+
 static void
 check_emit_usable (NMBluezDevice *self)
 {
 	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
 	gboolean new_usable;
 
-	new_usable = (priv->initialized && priv->capabilities && priv->name && priv->address && priv->connections);
+	/* only expect the supported capabilities set. */
+	g_assert ((priv->capabilities & ~(  NM_BT_CAPABILITY_NAP
+#if WITH_BLUEZ4
+	                                  | NM_BT_CAPABILITY_DUN
+#endif
+	                                 )) == NM_BT_CAPABILITY_NONE);
+
+	new_usable = (priv->initialized && priv->capabilities && priv->name &&
+#if ! WITH_BLUEZ4
+	              priv->adapter && priv->adapter_powered &&
+#endif
+	              priv->dbus_connection && priv->address);
+
+	if (!new_usable)
+		goto END;
+
+	if (priv->connections)
+		goto END;
+
+	if (!(priv->capabilities & NM_BT_CAPABILITY_NAP)) {
+		/* non NAP devices are only usable, if they already have a connection. */
+		new_usable = FALSE;
+		goto END;
+	}
+
+	pan_connection_check_create (self);
+	new_usable = !!priv->pan_connection;
+
+END:
 	if (new_usable != priv->usable) {
 		priv->usable = new_usable;
 		g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_USABLE);
@@ -162,6 +324,10 @@ connection_compatible (NMBluezDevice *self, NMConnection *connection)
 	if (!s_bt)
 		return FALSE;
 
+	if (!priv->address) {
+		/* unless address is set, bin_address is not initialized. */
+		return FALSE;
+	}
 	bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt);
 	if (!bdaddr || bdaddr->len != ETH_ALEN)
 		return FALSE;
@@ -171,11 +337,11 @@ connection_compatible (NMBluezDevice *self, NMConnection *connection)
 	bt_type = nm_setting_bluetooth_get_connection_type (s_bt);
 	if (   g_str_equal (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN)
 	    && !(priv->capabilities & NM_BT_CAPABILITY_DUN))
-	    	return FALSE;
+		return FALSE;
 
 	if (   g_str_equal (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU)
 	    && !(priv->capabilities & NM_BT_CAPABILITY_NAP))
-	    	return FALSE;
+		return FALSE;
 
 	return TRUE;
 }
@@ -209,6 +375,9 @@ cp_connection_removed (NMConnectionProvider *provider,
 
 	if (g_slist_find (priv->connections, connection)) {
 		priv->connections = g_slist_remove (priv->connections, connection);
+		if (priv->pan_connection == connection) {
+			priv->pan_connection = NULL;
+		}
 		g_object_unref (connection);
 		check_emit_usable (self);
 	}
@@ -237,6 +406,165 @@ cp_connections_loaded (NMConnectionProvider *provider, NMBluezDevice *self)
 
 /***********************************************************/
 
+static void
+bluez_disconnect_cb (GDBusConnection *dbus_connection,
+                     GAsyncResult *res,
+                     gpointer user_data)
+{
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (user_data);
+	GError *error = NULL;
+	GVariant *variant;
+
+	variant = g_dbus_connection_call_finish (dbus_connection, res, &error);
+	if (!variant) {
+		nm_log_warn (LOGD_BT, "%s: failed to disconnect: %s", priv->address, error->message);
+		g_error_free (error);
+	} else
+		g_variant_unref (variant);
+}
+
+void
+nm_bluez_device_disconnect (NMBluezDevice *self)
+{
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+	GVariant *args = NULL;
+	const char *dbus_iface = BLUEZ_NETWORK_INTERFACE;
+
+	g_return_if_fail (priv->dbus_connection);
+
+#if ! WITH_BLUEZ4
+	g_return_if_fail (priv->connection_bt_type == NM_BT_CAPABILITY_NAP);
+#else
+	g_return_if_fail (priv->connection_bt_type == NM_BT_CAPABILITY_NAP || priv->connection_bt_type == NM_BT_CAPABILITY_DUN);
+
+	if (priv->connection_bt_type == NM_BT_CAPABILITY_DUN) {
+		/* Can't pass a NULL interface name through dbus to bluez, so just
+		 * ignore the disconnect if the interface isn't known.
+		 */
+		if (!priv->bt_iface)
+			return;
+
+		args = g_variant_new ("(s)", priv->bt_iface),
+		dbus_iface = BLUEZ_SERIAL_INTERFACE;
+	}
+#endif
+
+	g_dbus_connection_call (priv->dbus_connection,
+	                        BLUEZ_SERVICE,
+	                        priv->path,
+	                        dbus_iface,
+	                        "Disconnect",
+	                        args ? args : g_variant_new ("()"),
+	                        NULL,
+	                        G_DBUS_CALL_FLAGS_NONE,
+	                        10000,
+	                        NULL,
+	                        (GAsyncReadyCallback) bluez_disconnect_cb,
+	                        self);
+
+	priv->connection_bt_type = NM_BT_CAPABILITY_NONE;
+}
+
+static void
+bluez_connect_cb (GDBusConnection *dbus_connection,
+                  GAsyncResult *res,
+                  gpointer user_data)
+{
+	GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data);
+	GObject *result_object = g_async_result_get_source_object (G_ASYNC_RESULT (result));
+	NMBluezDevice *self = NM_BLUEZ_DEVICE (result_object);
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+	GError *error = NULL;
+	char *device;
+	GVariant *variant;
+
+	variant = g_dbus_connection_call_finish (dbus_connection, res, &error);
+
+	if (!variant) {
+		g_simple_async_result_take_error (result, error);
+	} else {
+		g_variant_get (variant, "(s)", &device);
+
+		g_simple_async_result_set_op_res_gpointer (result,
+		                                           g_strdup (device),
+		                                           g_free);
+		priv->bt_iface = device;
+		g_variant_unref (variant);
+	}
+
+	g_simple_async_result_complete (result);
+	g_object_unref (result);
+	g_object_unref (result_object);
+}
+
+void
+nm_bluez_device_connect_async (NMBluezDevice *self,
+                               NMBluetoothCapabilities connection_bt_type,
+                               GAsyncReadyCallback callback,
+                               gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+	const char *dbus_iface = BLUEZ_NETWORK_INTERFACE;
+	const char *connect_type = BLUETOOTH_CONNECT_NAP;
+
+	g_return_if_fail (priv->capabilities & connection_bt_type & (NM_BT_CAPABILITY_DUN | NM_BT_CAPABILITY_NAP));
+#if ! WITH_BLUEZ4
+	g_return_if_fail (connection_bt_type == NM_BT_CAPABILITY_NAP);
+#else
+	g_return_if_fail (connection_bt_type == NM_BT_CAPABILITY_NAP || connection_bt_type == NM_BT_CAPABILITY_DUN);
+
+	if (connection_bt_type == NM_BT_CAPABILITY_DUN) {
+		dbus_iface = BLUEZ_SERIAL_INTERFACE;
+		connect_type = BLUETOOTH_CONNECT_DUN;
+	}
+#endif
+
+	simple = g_simple_async_result_new (G_OBJECT (self),
+	                                    callback,
+	                                    user_data,
+	                                    nm_bluez_device_connect_async);
+
+	g_dbus_connection_call (priv->dbus_connection,
+	                        BLUEZ_SERVICE,
+	                        priv->path,
+	                        dbus_iface,
+	                        "Connect",
+	                        g_variant_new ("(s)", connect_type),
+	                        NULL,
+	                        G_DBUS_CALL_FLAGS_NONE,
+	                        20000,
+	                        NULL,
+	                        (GAsyncReadyCallback) bluez_connect_cb,
+	                        simple);
+
+	priv->connection_bt_type = connection_bt_type;
+}
+
+const char *
+nm_bluez_device_connect_finish (NMBluezDevice *self,
+                                GAsyncResult *result,
+                                GError **error)
+{
+	GSimpleAsyncResult *simple;
+	const char *device;
+
+	g_return_val_if_fail (g_simple_async_result_is_valid (result,
+	                                                      G_OBJECT (self),
+	                                                      nm_bluez_device_connect_async),
+	                      NULL);
+
+	simple = (GSimpleAsyncResult *) result;
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return NULL;
+
+	device = (const char *) g_simple_async_result_get_op_res_gpointer (simple);
+	return device;
+}
+
+/***********************************************************/
+
 static guint32
 convert_uuids_to_capabilities (const char **strings)
 {
@@ -249,9 +577,11 @@ convert_uuids_to_capabilities (const char **strings)
 		parts = g_strsplit (*iter, "-", -1);
 		if (parts && parts[0]) {
 			switch (g_ascii_strtoull (parts[0], NULL, 16)) {
+#if WITH_BLUEZ4
 			case 0x1103:
 				capabilities |= NM_BT_CAPABILITY_DUN;
 				break;
+#endif
 			case 0x1116:
 				capabilities |= NM_BT_CAPABILITY_NAP;
 				break;
@@ -266,7 +596,175 @@ convert_uuids_to_capabilities (const char **strings)
 }
 
 static void
-property_changed (DBusGProxy *proxy,
+_set_property_capabilities (NMBluezDevice *self, const char **uuids, gboolean notify)
+{
+	guint32 uint_val;
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+
+	uint_val = convert_uuids_to_capabilities (uuids);
+	if (priv->capabilities != uint_val) {
+		if (priv->capabilities) {
+			/* changing (relevant) capabilities is not supported and ignored -- except setting initially */
+			nm_log_warn (LOGD_BT, "ignore change of capabilities for Bluetooth device %s from %u to %u",
+			             priv->path, priv->capabilities, uint_val);
+			return;
+		}
+		nm_log_dbg (LOGD_BT, "set capabilities for Bluetooth device %s: %s%s%s", priv->path,
+		            uint_val & NM_BT_CAPABILITY_NAP ? "NAP" : "",
+		            ((uint_val & NM_BT_CAPABILITY_DUN) && (uint_val &NM_BT_CAPABILITY_NAP)) ? " | " : "",
+		            uint_val & NM_BT_CAPABILITY_DUN ? "DUN" : "");
+		priv->capabilities = uint_val;
+		if (notify)
+			g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_CAPABILITIES);
+	}
+}
+
+/**
+ * priv->address can only be set one to a certain (non NULL) value. Every later attempt
+ * to reset it to another value will be ignored and a warning will be logged.
+ *
+ * When setting the address for the first time, we also set bin_address.
+ **/
+static void
+_set_property_address (NMBluezDevice *self, const char *addr)
+{
+	struct ether_addr *tmp;
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+
+	if (g_strcmp0 (priv->address, addr) == 0)
+		return;
+
+	if (!addr) {
+		nm_log_warn (LOGD_BT, "[%s] cannot reset address from '%s' to NULL", priv->path, priv->address);
+		return;
+	}
+
+	if (priv->address != NULL) {
+		nm_log_warn (LOGD_BT, "[%s] cannot reset address from '%s' to '%s'", priv->path, priv->address, addr);
+		return;
+	}
+
+	tmp = ether_aton (addr);
+	if (!tmp) {
+		if (priv->address)
+			nm_log_warn (LOGD_BT, "[%s] cannot reset address from '%s' to '%s' (invalid value)", priv->path, priv->address, addr);
+		else
+			nm_log_warn (LOGD_BT, "[%s] cannot reset address from NULL to '%s' (invalid value)", priv->path, addr);
+		return;
+	}
+	memcpy (priv->bin_address, tmp->ether_addr_octet, ETH_ALEN);
+	priv->address = g_strdup (addr);
+	return;
+}
+
+#if ! WITH_BLUEZ4
+static void
+adapter_properties_changed (GDBusProxy *proxy5,
+                            GVariant *changed_properties,
+                            GStrv invalidated_properties,
+                            gpointer user_data)
+{
+	NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data);
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+	GVariantIter i;
+	const char *property;
+	GVariant *v;
+
+	g_variant_iter_init (&i, changed_properties);
+	while (g_variant_iter_next (&i, "{&sv}", &property, &v)) {
+		if (!strcmp (property, "Powered")) {
+			gboolean powered = g_variant_get_boolean (v);
+			if (priv->adapter_powered != powered)
+				priv->adapter_powered = powered;
+		}
+		g_variant_unref (v);
+	}
+
+	check_emit_usable (self);
+}
+
+static void
+on_adapter_acquired (GObject *object, GAsyncResult *res, NMBluezDevice *self)
+{
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+	GError *error;
+	GVariant *v;
+
+	priv->adapter = g_dbus_proxy_new_for_bus_finish (res, &error);
+	if (!priv->adapter) {
+		nm_log_warn (LOGD_BT, "failed to acquire adapter proxy: %s.", error->message);
+		g_clear_error (&error);
+		g_signal_emit (self, signals[INITIALIZED], 0, FALSE);
+	} else {
+		g_signal_connect (priv->adapter, "g-properties-changed",
+		                  G_CALLBACK (adapter_properties_changed), self);
+
+		/* Check adapter's powered state */
+		v = g_dbus_proxy_get_cached_property (priv->adapter, "Powered");
+		priv->adapter_powered = v ? g_variant_get_boolean (v) : FALSE;
+		if (v)
+			g_variant_unref (v);
+
+		priv->initialized = TRUE;
+		g_signal_emit (self, signals[INITIALIZED], 0, TRUE);
+
+		check_emit_usable (self);
+	}
+
+	g_object_unref (self);
+}
+
+static void
+properties_changed (GDBusProxy *proxy5,
+                    GVariant *changed_properties,
+                    GStrv invalidated_properties,
+                    gpointer user_data)
+{
+	NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data);
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+	GVariantIter i;
+	const char *property;
+	const char *str;
+	GVariant *v;
+	gint int_val;
+	const char **strv;
+
+	g_object_freeze_notify (G_OBJECT (self));
+	g_variant_iter_init (&i, changed_properties);
+	while (g_variant_iter_next (&i, "{&sv}", &property, &v)) {
+		if (!strcmp (property, "Name")) {
+			str = g_variant_get_string (v, NULL);
+			if (g_strcmp0 (priv->name, str)) {
+				g_free (priv->name);
+				priv->name = g_strdup (str);
+				g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_NAME);
+			}
+		} else if (!strcmp (property, "RSSI")) {
+			int_val = g_variant_get_int16 (v);
+			if (priv->rssi != int_val) {
+				priv->rssi = int_val;
+				g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_RSSI);
+			}
+		} else if (!strcmp (property, "UUIDs")) {
+			strv = g_variant_get_strv (v, NULL);
+			_set_property_capabilities (self, strv, TRUE);
+			g_free (strv);
+		} else if (!strcmp (property, "Connected")) {
+			gboolean connected = g_variant_get_boolean (v);
+			if (priv->connected != connected) {
+				priv->connected = connected;
+				g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_CONNECTED);
+			}
+		}
+		g_variant_unref (v);
+	}
+	g_object_thaw_notify (G_OBJECT (self));
+
+	check_emit_usable (self);
+}
+#else
+static void
+property_changed (DBusGProxy *proxy4,
                   const char *property,
                   GValue *value,
                   gpointer user_data)
@@ -274,47 +772,100 @@ property_changed (DBusGProxy *proxy,
 	NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data);
 	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
 	const char *str;
-	guint32 uint_val;
 	gint int_val;
 
-	if (!strcmp (property, "Name")) {
-		str = g_value_get_string (value);
-		if (   (!priv->name && str)
-		    || (priv->name && !str)
-		    || (priv->name && str && strcmp (priv->name, str))) {
-			g_free (priv->name);
-			priv->name = g_strdup (str);
-			g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_NAME);
-		}
-	} else if (!strcmp (property, "RSSI")) {
-		int_val = g_value_get_int (value);
-		if (priv->rssi != int_val) {
-			priv->rssi = int_val;
-			g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_RSSI);
-		}
-	} else if (!strcmp (property, "UUIDs")) {
-		uint_val = convert_uuids_to_capabilities ((const char **) g_value_get_boxed (value));
-		if (priv->capabilities != uint_val) {
-			priv->capabilities = uint_val;
-			g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_CAPABILITIES);
+	g_object_freeze_notify (G_OBJECT (self));
+	{
+		if (!strcmp (property, "Name")) {
+			str = g_value_get_string (value);
+			if (   (!priv->name && str)
+			    || (priv->name && !str)
+			    || (priv->name && str && strcmp (priv->name, str))) {
+				g_free (priv->name);
+				priv->name = g_strdup (str);
+				g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_NAME);
+			}
+		} else if (!strcmp (property, "RSSI")) {
+			int_val = g_value_get_int (value);
+			if (priv->rssi != int_val) {
+				priv->rssi = int_val;
+				g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_RSSI);
+			}
+		} else if (!strcmp (property, "UUIDs")) {
+			_set_property_capabilities (self, (const char **) g_value_get_boxed (value), TRUE);
+		} else if (!strcmp (property, "Connected")) {
+			gboolean connected = g_value_get_boolean (value);
+			if (priv->connected != connected) {
+				priv->connected = connected;
+				g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_CONNECTED);
+			}
 		}
 	}
+	g_object_thaw_notify (G_OBJECT (self));
 
 	check_emit_usable (self);
 }
+#endif
+
+#if ! WITH_BLUEZ4
+static void
+query_properties (NMBluezDevice *self)
+{
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+	GVariant *v;
+	const char **uuids;
+
+	v = g_dbus_proxy_get_cached_property (priv->proxy5, "Address");
+	_set_property_address (self, v ? g_variant_get_string (v, NULL) : NULL);
+	if (v)
+		g_variant_unref (v);
+
+	v = g_dbus_proxy_get_cached_property (priv->proxy5, "Name");
+	priv->name = v ? g_variant_dup_string (v, NULL) : NULL;
+	if (v)
+		g_variant_unref (v);
+
+	v = g_dbus_proxy_get_cached_property (priv->proxy5, "RSSI");
+	priv->rssi = v ? g_variant_get_int16 (v) : 0;
+	if (v)
+		g_variant_unref (v);
+
+	v = g_dbus_proxy_get_cached_property (priv->proxy5, "UUIDs");
+	if (v) {
+		uuids = g_variant_get_strv (v, NULL);
+		_set_property_capabilities (self, uuids, FALSE);
+		g_variant_unref (v);
+	} else
+		priv->capabilities = NM_BT_CAPABILITY_NONE;
+
+	v = g_dbus_proxy_get_cached_property (priv->proxy5, "Adapter");
+	if (v) {
+		g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+		                          G_DBUS_PROXY_FLAGS_NONE,
+		                          NULL,
+		                          BLUEZ_SERVICE,
+		                          g_variant_get_string (v, NULL),
+		                          BLUEZ_ADAPTER_INTERFACE,
+		                          NULL,
+		                          (GAsyncReadyCallback) on_adapter_acquired,
+		                          g_object_ref (self));
+		g_variant_unref (v);
+	}
 
+	/* Check if any connections match this device */
+	cp_connections_loaded (priv->provider, self);
+}
+#else
 static void
-get_properties_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
+get_properties_cb (DBusGProxy *proxy4, DBusGProxyCall *call, gpointer user_data)
 {
 	NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data);
 	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
 	GHashTable *properties = NULL;
 	GError *err = NULL;
 	GValue *value;
-	const char **uuids;
-	struct ether_addr *tmp;
 
-	if (!dbus_g_proxy_end_call (proxy, call, &err,
+	if (!dbus_g_proxy_end_call (proxy4, call, &err,
 	                            DBUS_TYPE_G_MAP_OF_VARIANT, &properties,
 	                            G_TYPE_INVALID)) {
 		nm_log_warn (LOGD_BT, "bluez error getting device properties: %s",
@@ -325,12 +876,7 @@ get_properties_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
 	}
 
 	value = g_hash_table_lookup (properties, "Address");
-	priv->address = value ? g_value_dup_string (value) : NULL;
-	if (priv->address) {
-		tmp = ether_aton (priv->address);
-		g_assert (tmp);
-		memcpy (priv->bin_address, tmp->ether_addr_octet, ETH_ALEN);
-	}
+	_set_property_address (self, value ? g_value_get_string (value) : NULL);
 
 	value = g_hash_table_lookup (properties, "Name");
 	priv->name = value ? g_value_dup_string (value) : NULL;
@@ -340,8 +886,7 @@ get_properties_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
 
 	value = g_hash_table_lookup (properties, "UUIDs");
 	if (value) {
-		uuids = (const char **) g_value_get_boxed (value);
-		priv->capabilities = convert_uuids_to_capabilities (uuids);
+		_set_property_capabilities (self, (const char **) g_value_get_boxed (value), FALSE);
 	} else
 		priv->capabilities = NM_BT_CAPABILITY_NONE;
 
@@ -362,7 +907,7 @@ query_properties (NMBluezDevice *self)
 	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
 	DBusGProxyCall *call;
 
-	call = dbus_g_proxy_begin_call (priv->proxy, "GetProperties",
+	call = dbus_g_proxy_begin_call (priv->proxy4, "GetProperties",
 	                                get_properties_cb,
 	                                self,
 	                                NULL, G_TYPE_INVALID);
@@ -371,6 +916,49 @@ query_properties (NMBluezDevice *self)
 		             priv->path);
 	}
 }
+#endif
+
+
+#if ! WITH_BLUEZ4
+static void
+on_proxy_acquired (GObject *object, GAsyncResult *res, NMBluezDevice *self)
+{
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+	GError *error;
+
+	priv->proxy5 = g_dbus_proxy_new_for_bus_finish (res, &error);
+
+	if (!priv->proxy5) {
+		nm_log_warn (LOGD_BT, "failed to acquire device proxy: %s.", error->message);
+		g_clear_error (&error);
+		g_signal_emit (self, signals[INITIALIZED], 0, FALSE);
+	} else {
+		g_signal_connect (priv->proxy5, "g-properties-changed",
+		                  G_CALLBACK (properties_changed), self);
+
+		query_properties (self);
+	}
+	g_object_unref (self);
+}
+#endif
+
+static void
+on_bus_acquired (GObject *object, GAsyncResult *res, NMBluezDevice *self)
+{
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+	GError *error = NULL;
+
+	priv->dbus_connection = g_bus_get_finish (res, &error);
+
+	if (!priv->dbus_connection) {
+		nm_log_warn (LOGD_BT, "failed to acquire bus connection: %s.", error->message);
+		g_clear_error (&error);
+		g_signal_emit (self, signals[INITIALIZED], 0, FALSE);
+		return;
+	}
+
+	check_emit_usable (self);
+}
 
 /********************************************************************/
 
@@ -379,8 +967,10 @@ nm_bluez_device_new (const char *path, NMConnectionProvider *provider)
 {
 	NMBluezDevice *self;
 	NMBluezDevicePrivate *priv;
+#if WITH_BLUEZ4
 	NMDBusManager *dbus_mgr;
 	DBusGConnection *connection;
+#endif
 
 	g_return_val_if_fail (path != NULL, NULL);
 	g_return_val_if_fail (provider != NULL, NULL);
@@ -415,25 +1005,43 @@ nm_bluez_device_new (const char *path, NMConnectionProvider *provider)
 	                  G_CALLBACK (cp_connections_loaded),
 	                  self);
 
+	g_bus_get (G_BUS_TYPE_SYSTEM,
+	           NULL,
+	           (GAsyncReadyCallback) on_bus_acquired,
+	           self);
+
+#if ! WITH_BLUEZ4
+	g_object_ref (self);
+	g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+	                          G_DBUS_PROXY_FLAGS_NONE,
+	                          NULL,
+	                          BLUEZ_SERVICE,
+	                          priv->path,
+	                          BLUEZ_DEVICE_INTERFACE,
+	                          NULL,
+	                          (GAsyncReadyCallback) on_proxy_acquired,
+	                          self);
+#else
 	dbus_mgr = nm_dbus_manager_get ();
 	connection = nm_dbus_manager_get_connection (dbus_mgr);
 
-	priv->proxy = dbus_g_proxy_new_for_name (connection,
-	                                         BLUEZ_SERVICE,
-	                                         priv->path,
-	                                         BLUEZ_DEVICE_INTERFACE);
+	priv->proxy4 = dbus_g_proxy_new_for_name (connection,
+	                                          BLUEZ_SERVICE,
+	                                          priv->path,
+	                                          BLUEZ_DEVICE_INTERFACE);
 	g_object_unref (dbus_mgr);
 
 	dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_BOXED,
 	                                   G_TYPE_NONE,
 	                                   G_TYPE_STRING, G_TYPE_VALUE,
 	                                   G_TYPE_INVALID);
-	dbus_g_proxy_add_signal (priv->proxy, "PropertyChanged",
+	dbus_g_proxy_add_signal (priv->proxy4, "PropertyChanged",
 	                         G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->proxy, "PropertyChanged",
+	dbus_g_proxy_connect_signal (priv->proxy4, "PropertyChanged",
 	                             G_CALLBACK (property_changed), self, NULL);
 
 	query_properties (self);
+#endif
 	return self;
 }
 
@@ -457,6 +1065,11 @@ dispose (GObject *object)
 	g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_updated, self);
 	g_signal_handlers_disconnect_by_func (priv->provider, cp_connections_loaded, self);
 
+#if ! WITH_BLUEZ4
+	g_clear_object (&priv->adapter);
+#endif
+	g_clear_object (&priv->dbus_connection);
+
 	G_OBJECT_CLASS (nm_bluez_device_parent_class)->dispose (object);
 }
 
@@ -468,7 +1081,12 @@ finalize (GObject *object)
 	g_free (priv->path);
 	g_free (priv->address);
 	g_free (priv->name);
-	g_object_unref (priv->proxy);
+	g_free (priv->bt_iface);
+#if ! WITH_BLUEZ4
+	g_object_unref (priv->proxy5);
+#else
+	g_object_unref (priv->proxy4);
+#endif
 
 	G_OBJECT_CLASS (nm_bluez_device_parent_class)->finalize (object);
 }
@@ -498,6 +1116,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_USABLE:
 		g_value_set_boolean (value, priv->usable);
 		break;
+	case PROP_CONNECTED:
+		g_value_set_boolean (value, priv->connected);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -583,13 +1204,20 @@ nm_bluez_device_class_init (NMBluezDeviceClass *config_class)
 		                       FALSE,
 		                       G_PARAM_READABLE));
 
+	g_object_class_install_property
+		(object_class, PROP_CONNECTED,
+		 g_param_spec_boolean (NM_BLUEZ_DEVICE_CONNECTED,
+		                       "Connected",
+		                       "Connected",
+		                       FALSE,
+		                       G_PARAM_READABLE));
+
 	/* Signals */
 	signals[INITIALIZED] = g_signal_new ("initialized",
 	                                     G_OBJECT_CLASS_TYPE (object_class),
 	                                     G_SIGNAL_RUN_LAST,
 	                                     G_STRUCT_OFFSET (NMBluezDeviceClass, initialized),
-	                                     NULL, NULL,
-	                                     g_cclosure_marshal_VOID__BOOLEAN,
+	                                     NULL, NULL, NULL,
 	                                     G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
 }
 
diff --git a/src/bluez-manager/nm-bluez-device.h b/src/bluez-manager/nm-bluez-device.h
index 18f9fc30..11add389 100644
--- a/src/bluez-manager/nm-bluez-device.h
+++ b/src/bluez-manager/nm-bluez-device.h
@@ -23,7 +23,9 @@
 
 #include <glib.h>
 #include <glib-object.h>
+#include <gio/gio.h>
 
+#include <config.h>
 #include "nm-connection.h"
 #include "nm-connection-provider.h"
 
@@ -40,6 +42,7 @@
 #define NM_BLUEZ_DEVICE_CAPABILITIES "capabilities"
 #define NM_BLUEZ_DEVICE_RSSI         "rssi"
 #define NM_BLUEZ_DEVICE_USABLE       "usable"
+#define NM_BLUEZ_DEVICE_CONNECTED    "connected"
 
 typedef struct {
 	GObject parent;
@@ -74,5 +77,21 @@ guint32 nm_bluez_device_get_capabilities (NMBluezDevice *self);
 
 gint nm_bluez_device_get_rssi (NMBluezDevice *self);
 
+gboolean nm_bluez_device_get_connected (NMBluezDevice *self);
+
+void
+nm_bluez_device_connect_async (NMBluezDevice *self,
+                               NMBluetoothCapabilities connection_bt_type,
+                               GAsyncReadyCallback callback,
+                               gpointer user_data);
+
+const char *
+nm_bluez_device_connect_finish (NMBluezDevice *self,
+                                GAsyncResult *result,
+                                GError **error);
+
+void
+nm_bluez_device_disconnect (NMBluezDevice *self);
+
 #endif /* NM_BLUEZ_DEVICE_H */
 
diff --git a/src/bluez-manager/nm-bluez-manager.c b/src/bluez-manager/nm-bluez-manager.c
index a6848631..3801d5ee 100644
--- a/src/bluez-manager/nm-bluez-manager.c
+++ b/src/bluez-manager/nm-bluez-manager.c
@@ -17,21 +17,20 @@
  *
  * Copyright (C) 2007 - 2008 Novell, Inc.
  * Copyright (C) 2007 - 2012 Red Hat, Inc.
+ * Copyright (C) 2013 Intel Corporation.
  */
 
 #include <signal.h>
 #include <string.h>
 #include <stdlib.h>
-#include <dbus/dbus-glib.h>
+#include <gio/gio.h>
 
 #include "nm-logging.h"
-#include "nm-dbus-glib-types.h"
-#include "nm-marshal.h"
 #include "nm-bluez-manager.h"
-#include "nm-bluez-adapter.h"
-#include "nm-dbus-manager.h"
+#include "nm-bluez-device.h"
 #include "nm-bluez-common.h"
 
+#include "nm-dbus-manager.h"
 
 typedef struct {
 	NMDBusManager *dbus_mgr;
@@ -39,9 +38,9 @@ typedef struct {
 
 	NMConnectionProvider *provider;
 
-	DBusGProxy *proxy;
+	GDBusProxy *proxy;
 
-	NMBluezAdapter *adapter;
+	GHashTable *devices;
 } NMBluezManagerPrivate;
 
 #define NM_BLUEZ_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerPrivate))
@@ -57,11 +56,14 @@ enum {
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
-static void
+static void device_initialized (NMBluezDevice *device, gboolean success, NMBluezManager *self);
+static void device_usable (NMBluezDevice *device, GParamSpec *pspec, NMBluezManager *self);
 
+static void
 emit_bdaddr_added (NMBluezManager *self, NMBluezDevice *device)
 {
 	g_signal_emit (self, signals[BDADDR_ADDED], 0,
+	               device,
 	               nm_bluez_device_get_address (device),
 	               nm_bluez_device_get_name (device),
 	               nm_bluez_device_get_path (device),
@@ -72,173 +74,216 @@ void
 nm_bluez_manager_query_devices (NMBluezManager *self)
 {
 	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
-	GSList *devices, *iter;
+	NMBluezDevice *device;
+	GHashTableIter iter;
 
-	if (!priv->adapter)
-		return;
+	g_hash_table_iter_init (&iter, priv->devices);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) {
+		if (nm_bluez_device_get_usable (device))
+			emit_bdaddr_added (self, device);
+	}
+}
 
-	devices = nm_bluez_adapter_get_devices (priv->adapter);
-	for (iter = devices; iter; iter = g_slist_next (iter))
-		emit_bdaddr_added (self, NM_BLUEZ_DEVICE (iter->data));
-	g_slist_free (devices);
+static void
+remove_device (NMBluezManager *self, NMBluezDevice *device)
+{
+	if (nm_bluez_device_get_usable (device)) {
+		g_signal_emit (self, signals[BDADDR_REMOVED], 0,
+		               nm_bluez_device_get_address (device),
+		               nm_bluez_device_get_path (device));
+	}
+	g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_initialized), self);
+	g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_usable), self);
 }
 
 static void
-device_added (NMBluezAdapter *adapter, NMBluezDevice *device, gpointer user_data)
+remove_all_devices (NMBluezManager *self)
 {
-	emit_bdaddr_added (NM_BLUEZ_MANAGER (user_data), device);
+	GHashTableIter iter;
+	NMBluezDevice *device;
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+
+	g_hash_table_iter_init (&iter, priv->devices);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) {
+		g_hash_table_iter_steal (&iter);
+		remove_device (self, device);
+		g_object_unref (device);
+	}
 }
 
 static void
-device_removed (NMBluezAdapter *adapter, NMBluezDevice *device, gpointer user_data)
+device_usable (NMBluezDevice *device, GParamSpec *pspec, NMBluezManager *self)
 {
-	NMBluezManager *self = NM_BLUEZ_MANAGER (user_data);
+	gboolean usable = nm_bluez_device_get_usable (device);
+
+	nm_log_dbg (LOGD_BT, "(%s): bluez device now %s",
+	            nm_bluez_device_get_path (device),
+	            usable ? "usable" : "unusable");
+
+	if (usable) {
+		nm_log_dbg (LOGD_BT, "(%s): bluez device address %s",
+				    nm_bluez_device_get_path (device),
+				    nm_bluez_device_get_address (device));
+		emit_bdaddr_added (self, device);
+	} else
+		g_signal_emit (self, signals[BDADDR_REMOVED], 0,
+		               nm_bluez_device_get_address (device),
+		               nm_bluez_device_get_path (device));
+}
 
-	g_signal_emit (self, signals[BDADDR_REMOVED], 0,
-	               nm_bluez_device_get_address (device),
-	               nm_bluez_device_get_path (device));
+static void
+device_initialized (NMBluezDevice *device, gboolean success, NMBluezManager *self)
+{
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+
+	nm_log_dbg (LOGD_BT, "(%s): bluez device %s",
+	            nm_bluez_device_get_path (device),
+	            success ? "initialized" : "failed to initialize");
+	if (!success)
+		g_hash_table_remove (priv->devices, nm_bluez_device_get_path (device));
 }
 
 static void
-adapter_initialized (NMBluezAdapter *adapter, gboolean success, gpointer user_data)
+device_added (GDBusProxy *proxy, const gchar *path, NMBluezManager *self)
 {
-	NMBluezManager *self = NM_BLUEZ_MANAGER (user_data);
 	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+	NMBluezDevice *device;
+
+	device = nm_bluez_device_new (path, priv->provider);
+	g_signal_connect (device, "initialized", G_CALLBACK (device_initialized), self);
+	g_signal_connect (device, "notify::usable", G_CALLBACK (device_usable), self);
+	g_hash_table_insert (priv->devices, (gpointer) nm_bluez_device_get_path (device), device);
+
+	nm_log_dbg (LOGD_BT, "(%s): new bluez device found", path);
+}
 
-	if (success) {
-		GSList *devices, *iter;
+static void
+device_removed (GDBusProxy *proxy, const gchar *path, NMBluezManager *self)
+{
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+	NMBluezDevice *device;
 
-		devices = nm_bluez_adapter_get_devices (adapter);
-		for (iter = devices; iter; iter = g_slist_next (iter))
-			emit_bdaddr_added (self, NM_BLUEZ_DEVICE (iter->data));
-		g_slist_free (devices);
+	nm_log_dbg (LOGD_BT, "(%s): bluez device removed", path);
 
-		g_signal_connect (adapter, "device-added", G_CALLBACK (device_added), self);
-		g_signal_connect (adapter, "device-removed", G_CALLBACK (device_removed), self);
-	} else {
-		g_object_unref (priv->adapter);
-		priv->adapter = NULL;
+	device = g_hash_table_lookup (priv->devices, path);
+	if (device) {
+		g_hash_table_steal (priv->devices, nm_bluez_device_get_path (device));
+		remove_device (NM_BLUEZ_MANAGER (self), device);
+		g_object_unref (device);
 	}
 }
 
 static void
-adapter_removed (DBusGProxy *proxy, const char *path, NMBluezManager *self)
+object_manager_g_signal (GDBusProxy     *proxy,
+                         gchar          *sender_name,
+                         gchar          *signal_name,
+                         GVariant       *parameters,
+                         NMBluezManager *self)
 {
-	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+	GVariant *variant;
+	const gchar *path;
 
-	if (priv->adapter && !strcmp (path, nm_bluez_adapter_get_path (priv->adapter))) {
-		if (nm_bluez_adapter_get_initialized (priv->adapter)) {
-			GSList *devices, *iter;
+	if (!strcmp (signal_name, "InterfacesRemoved")) {
+		const gchar **ifaces;
+		gsize i, length;
 
-			devices = nm_bluez_adapter_get_devices (priv->adapter);
-			for (iter = devices; iter; iter = g_slist_next (iter)) {
-				NMBluezDevice *device = NM_BLUEZ_DEVICE (iter->data);
+		g_variant_get (parameters, "(&o*)", &path, &variant);
 
-				g_signal_emit (self, signals[BDADDR_REMOVED], 0,
-				               nm_bluez_device_get_address (device),
-				               nm_bluez_device_get_path (device));
+		ifaces = g_variant_get_strv (variant, &length);
+
+		for (i = 0; i < length; i++) {
+			if (!strcmp (ifaces[i], BLUEZ_DEVICE_INTERFACE)) {
+				device_removed (proxy, path, self);
+				break;
 			}
-			g_slist_free (devices);
 		}
 
-		g_object_unref (priv->adapter);
-		priv->adapter = NULL;
+		g_free (ifaces);
+
+	} else if (!strcmp (signal_name, "InterfacesAdded")) {
+		g_variant_get (parameters, "(&o*)", &path, &variant);
+
+		if (g_variant_lookup_value (variant, BLUEZ_DEVICE_INTERFACE,
+		                            G_VARIANT_TYPE_DICTIONARY))
+			device_added (proxy, path, self);
 	}
 }
 
 static void
-default_adapter_changed (DBusGProxy *proxy, const char *path, NMBluezManager *self)
+get_managed_objects_cb (GDBusProxy *proxy,
+                        GAsyncResult *res,
+                        NMBluezManager *self)
 {
-	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
-	const char *cur_path = NULL;
-
-	if (priv->adapter)
-		cur_path = nm_bluez_adapter_get_path (priv->adapter);
-
-	if (cur_path) {
-		if (!path || strcmp (path, cur_path)) {
-			/* Default adapter changed */
-			adapter_removed (priv->proxy, cur_path, self);
-		} else {
-			/* This adapter is already the default */
-			return;
+	GVariant *variant, *ifaces;
+	GVariantIter i;
+	GError *error = NULL;
+	const char *path;
+
+	variant = g_dbus_proxy_call_finish (proxy, res, &error);
+
+	if (!variant) {
+		nm_log_warn (LOGD_BT, "Couldn't get managed objects: %s",
+		             error && error->message ? error->message : "(unknown)");
+		g_clear_error (&error);
+		return;
+	}
+	g_variant_iter_init (&i, g_variant_get_child_value (variant, 0));
+	while ((g_variant_iter_next (&i, "{&o*}", &path, &ifaces))) {
+		if (g_variant_lookup_value (ifaces, BLUEZ_DEVICE_INTERFACE,
+		                            G_VARIANT_TYPE_DICTIONARY)) {
+			device_added (proxy, path, self);
 		}
 	}
 
-	/* Add the new default adapter */
-	if (path) {
-		priv->adapter = nm_bluez_adapter_new (path, priv->provider);
-		g_signal_connect (priv->adapter, "initialized", G_CALLBACK (adapter_initialized), self);
-	}
+	g_variant_unref (variant);
 }
 
 static void
-default_adapter_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
+on_proxy_acquired (GObject *object,
+                   GAsyncResult *res,
+                   NMBluezManager *self)
 {
-	NMBluezManager *self = NM_BLUEZ_MANAGER (user_data);
 	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
-	const char *default_adapter = NULL;
-	GError *err = NULL;
-
-	if (!dbus_g_proxy_end_call (proxy, call, &err,
-	                            DBUS_TYPE_G_OBJECT_PATH, &default_adapter,
-	                            G_TYPE_INVALID)) {
-		/* Ignore "No such adapter" errors; just means bluetooth isn't active */
-		if (   !dbus_g_error_has_name (err, "org.bluez.Error.NoSuchAdapter")
-		    && !dbus_g_error_has_name (err, "org.freedesktop.systemd1.LoadFailed")
-		    && !g_error_matches (err, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN)) {
-			nm_log_warn (LOGD_BT, "bluez error getting default adapter: %s",
-			             err && err->message ? err->message : "(unknown)");
-		}
-		g_error_free (err);
+	GError *error = NULL;
+
+	priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
+
+	if (!priv->proxy) {
+		nm_log_warn (LOGD_BT, "Couldn't acquire object manager proxy: %s",
+		             error && error->message ? error->message : "(unknown)");
+		g_clear_error (&error);
 		return;
 	}
 
-	default_adapter_changed (priv->proxy, default_adapter, self);
-}
-
-static void
-query_default_adapter (NMBluezManager *self)
-{
-	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
-	DBusGProxyCall *call;
-
-	call = dbus_g_proxy_begin_call (priv->proxy, "DefaultAdapter",
-	                                default_adapter_cb,
-	                                self,
-	                                NULL, G_TYPE_INVALID);
-	if (!call)
-		nm_log_warn (LOGD_BT, "failed to request default Bluetooth adapter.");
+	/* Get already managed devices. */
+	g_dbus_proxy_call (priv->proxy, "GetManagedObjects",
+	                   NULL,
+	                   G_DBUS_CALL_FLAGS_NONE,
+	                   -1,
+	                   NULL,
+	                   (GAsyncReadyCallback) get_managed_objects_cb,
+	                   self);
+
+	g_signal_connect (priv->proxy, "g-signal",
+	                  G_CALLBACK (object_manager_g_signal), self);
 }
 
 static void
 bluez_connect (NMBluezManager *self)
 {
 	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
-	DBusGConnection *connection;
 
 	g_return_if_fail (priv->proxy == NULL);
 
-	connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
-	if (!connection)
-		return;
-
-	priv->proxy = dbus_g_proxy_new_for_name (connection,
-	                                         BLUEZ_SERVICE,
-	                                         BLUEZ_MANAGER_PATH,
-	                                         BLUEZ_MANAGER_INTERFACE);
-
-	dbus_g_proxy_add_signal (priv->proxy, "AdapterRemoved",
-	                         DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->proxy, "AdapterRemoved",
-	                             G_CALLBACK (adapter_removed), self, NULL);
-
-	dbus_g_proxy_add_signal (priv->proxy, "DefaultAdapterChanged",
-	                         DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->proxy, "DefaultAdapterChanged",
-	                             G_CALLBACK (default_adapter_changed), self, NULL);
-
-	query_default_adapter (self);
+	g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+	                          G_DBUS_PROXY_FLAGS_NONE,
+	                          NULL,
+	                          BLUEZ_SERVICE,
+	                          BLUEZ_MANAGER_PATH,
+	                          OBJECT_MANAGER_INTERFACE,
+	                          NULL,
+	                          (GAsyncReadyCallback) on_proxy_acquired,
+	                          self);
 }
 
 static void
@@ -257,14 +302,9 @@ name_owner_changed_cb (NMDBusManager *dbus_mgr,
 	if (strcmp (BLUEZ_SERVICE, name))
 		return;
 
-	if (!old_owner_good && new_owner_good)
-		query_default_adapter (self);
-	else if (old_owner_good && !new_owner_good) {
-		/* Throwing away the adapter removes all devices too */
-		if (priv->adapter) {
-			g_object_unref (priv->adapter);
-			priv->adapter = NULL;
-		}
+	if (old_owner_good && !new_owner_good) {
+		if (priv->devices)
+			remove_all_devices (self);
 	}
 }
 
@@ -278,10 +318,10 @@ bluez_cleanup (NMBluezManager *self, gboolean do_signal)
 		priv->proxy = NULL;
 	}
 
-	if (priv->adapter) {
-		g_object_unref (priv->adapter);
-		priv->adapter = NULL;
-	}
+	if (do_signal)
+		remove_all_devices (self);
+	else
+		g_hash_table_remove_all (priv->devices);
 }
 
 static void
@@ -335,6 +375,9 @@ nm_bluez_manager_init (NMBluezManager *self)
 	                  self);
 
 	bluez_connect (self);
+
+	priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
+	                                       NULL, g_object_unref);
 }
 
 static void
@@ -348,13 +391,23 @@ dispose (GObject *object)
 	if (priv->dbus_mgr) {
 		g_signal_handlers_disconnect_by_func (priv->dbus_mgr, name_owner_changed_cb, self);
 		g_signal_handlers_disconnect_by_func (priv->dbus_mgr, dbus_connection_changed_cb, self);
-		g_object_unref (priv->dbus_mgr);
+		priv->dbus_mgr = NULL;
 	}
 
 	G_OBJECT_CLASS (nm_bluez_manager_parent_class)->dispose (object);
 }
 
 static void
+finalize (GObject *object)
+{
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (object);
+
+	g_hash_table_destroy (priv->devices);
+
+	G_OBJECT_CLASS (nm_bluez_manager_parent_class)->finalize (object);
+}
+
+static void
 nm_bluez_manager_class_init (NMBluezManagerClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -363,6 +416,7 @@ nm_bluez_manager_class_init (NMBluezManagerClass *klass)
 
 	/* virtual methods */
 	object_class->dispose = dispose;
+	object_class->finalize = finalize;
 
 	/* Signals */
 	signals[BDADDR_ADDED] =
@@ -370,17 +424,15 @@ nm_bluez_manager_class_init (NMBluezManagerClass *klass)
 		              G_OBJECT_CLASS_TYPE (object_class),
 		              G_SIGNAL_RUN_FIRST,
 		              G_STRUCT_OFFSET (NMBluezManagerClass, bdaddr_added),
-		              NULL, NULL,
-		              _nm_marshal_VOID__STRING_STRING_STRING_UINT,
-		              G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT);
+		              NULL, NULL, NULL,
+		              G_TYPE_NONE, 5, G_TYPE_OBJECT, G_TYPE_STRING,
+		              G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT);
 
 	signals[BDADDR_REMOVED] =
 		g_signal_new (NM_BLUEZ_MANAGER_BDADDR_REMOVED,
 		              G_OBJECT_CLASS_TYPE (object_class),
 		              G_SIGNAL_RUN_FIRST,
 		              G_STRUCT_OFFSET (NMBluezManagerClass, bdaddr_removed),
-		              NULL, NULL,
-		              _nm_marshal_VOID__STRING_STRING,
+		              NULL, NULL, NULL,
 		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
 }
-
diff --git a/src/bluez-manager/nm-bluez-manager.h b/src/bluez-manager/nm-bluez-manager.h
index 2bfc971e..95e319c5 100644
--- a/src/bluez-manager/nm-bluez-manager.h
+++ b/src/bluez-manager/nm-bluez-manager.h
@@ -25,6 +25,7 @@
 #include <glib.h>
 #include <glib-object.h>
 
+#include  <config.h>
 #include  "nm-connection-provider.h"
 
 G_BEGIN_DECLS
diff --git a/src/bluez-manager/nm-bluez-adapter.c b/src/bluez-manager/nm-bluez4-adapter.c
index 4c36f3de..817df73d 100644
--- a/src/bluez-manager/nm-bluez-adapter.c
+++ b/src/bluez-manager/nm-bluez4-adapter.c
@@ -23,7 +23,7 @@
 
 #include "NetworkManager.h"
 #include "nm-dbus-manager.h"
-#include "nm-bluez-adapter.h"
+#include "nm-bluez4-adapter.h"
 #include "nm-bluez-device.h"
 #include "nm-bluez-common.h"
 #include "nm-dbus-glib-types.h"
diff --git a/src/bluez-manager/nm-bluez-adapter.h b/src/bluez-manager/nm-bluez4-adapter.h
index 8e53b40d..8e53b40d 100644
--- a/src/bluez-manager/nm-bluez-adapter.h
+++ b/src/bluez-manager/nm-bluez4-adapter.h
diff --git a/src/bluez-manager/nm-bluez4-manager.c b/src/bluez-manager/nm-bluez4-manager.c
new file mode 100644
index 00000000..bd1d251a
--- /dev/null
+++ b/src/bluez-manager/nm-bluez4-manager.c
@@ -0,0 +1,386 @@
+/* -*- 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 - 2008 Novell, Inc.
+ * Copyright (C) 2007 - 2012 Red Hat, Inc.
+ */
+
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dbus/dbus-glib.h>
+
+#include "nm-logging.h"
+#include "nm-dbus-glib-types.h"
+#include "nm-marshal.h"
+#include "nm-bluez-manager.h"
+#include "nm-bluez4-adapter.h"
+#include "nm-dbus-manager.h"
+#include "nm-bluez-common.h"
+
+
+typedef struct {
+	NMDBusManager *dbus_mgr;
+	gulong name_owner_changed_id;
+
+	NMConnectionProvider *provider;
+
+	DBusGProxy *proxy;
+
+	NMBluezAdapter *adapter;
+} NMBluezManagerPrivate;
+
+#define NM_BLUEZ_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerPrivate))
+
+G_DEFINE_TYPE (NMBluezManager, nm_bluez_manager, G_TYPE_OBJECT)
+
+enum {
+	BDADDR_ADDED,
+	BDADDR_REMOVED,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+
+emit_bdaddr_added (NMBluezManager *self, NMBluezDevice *device)
+{
+	g_signal_emit (self, signals[BDADDR_ADDED], 0,
+	               device,
+	               nm_bluez_device_get_address (device),
+	               nm_bluez_device_get_name (device),
+	               nm_bluez_device_get_path (device),
+	               nm_bluez_device_get_capabilities (device));
+}
+
+void
+nm_bluez_manager_query_devices (NMBluezManager *self)
+{
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+	GSList *devices, *iter;
+
+	if (!priv->adapter)
+		return;
+
+	devices = nm_bluez_adapter_get_devices (priv->adapter);
+	for (iter = devices; iter; iter = g_slist_next (iter))
+		emit_bdaddr_added (self, NM_BLUEZ_DEVICE (iter->data));
+	g_slist_free (devices);
+}
+
+static void
+device_added (NMBluezAdapter *adapter, NMBluezDevice *device, gpointer user_data)
+{
+	emit_bdaddr_added (NM_BLUEZ_MANAGER (user_data), device);
+}
+
+static void
+device_removed (NMBluezAdapter *adapter, NMBluezDevice *device, gpointer user_data)
+{
+	NMBluezManager *self = NM_BLUEZ_MANAGER (user_data);
+
+	g_signal_emit (self, signals[BDADDR_REMOVED], 0,
+	               nm_bluez_device_get_address (device),
+	               nm_bluez_device_get_path (device));
+}
+
+static void
+adapter_initialized (NMBluezAdapter *adapter, gboolean success, gpointer user_data)
+{
+	NMBluezManager *self = NM_BLUEZ_MANAGER (user_data);
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+
+	if (success) {
+		GSList *devices, *iter;
+
+		devices = nm_bluez_adapter_get_devices (adapter);
+		for (iter = devices; iter; iter = g_slist_next (iter))
+			emit_bdaddr_added (self, NM_BLUEZ_DEVICE (iter->data));
+		g_slist_free (devices);
+
+		g_signal_connect (adapter, "device-added", G_CALLBACK (device_added), self);
+		g_signal_connect (adapter, "device-removed", G_CALLBACK (device_removed), self);
+	} else {
+		g_object_unref (priv->adapter);
+		priv->adapter = NULL;
+	}
+}
+
+static void
+adapter_removed (DBusGProxy *proxy, const char *path, NMBluezManager *self)
+{
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+
+	if (priv->adapter && !strcmp (path, nm_bluez_adapter_get_path (priv->adapter))) {
+		if (nm_bluez_adapter_get_initialized (priv->adapter)) {
+			GSList *devices, *iter;
+
+			devices = nm_bluez_adapter_get_devices (priv->adapter);
+			for (iter = devices; iter; iter = g_slist_next (iter)) {
+				NMBluezDevice *device = NM_BLUEZ_DEVICE (iter->data);
+
+				g_signal_emit (self, signals[BDADDR_REMOVED], 0,
+				               nm_bluez_device_get_address (device),
+				               nm_bluez_device_get_path (device));
+			}
+			g_slist_free (devices);
+		}
+
+		g_object_unref (priv->adapter);
+		priv->adapter = NULL;
+	}
+}
+
+static void
+default_adapter_changed (DBusGProxy *proxy, const char *path, NMBluezManager *self)
+{
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+	const char *cur_path = NULL;
+
+	if (priv->adapter)
+		cur_path = nm_bluez_adapter_get_path (priv->adapter);
+
+	if (cur_path) {
+		if (!path || strcmp (path, cur_path)) {
+			/* Default adapter changed */
+			adapter_removed (priv->proxy, cur_path, self);
+		} else {
+			/* This adapter is already the default */
+			return;
+		}
+	}
+
+	/* Add the new default adapter */
+	if (path) {
+		priv->adapter = nm_bluez_adapter_new (path, priv->provider);
+		g_signal_connect (priv->adapter, "initialized", G_CALLBACK (adapter_initialized), self);
+	}
+}
+
+static void
+default_adapter_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
+{
+	NMBluezManager *self = NM_BLUEZ_MANAGER (user_data);
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+	const char *default_adapter = NULL;
+	GError *err = NULL;
+
+	if (!dbus_g_proxy_end_call (proxy, call, &err,
+	                            DBUS_TYPE_G_OBJECT_PATH, &default_adapter,
+	                            G_TYPE_INVALID)) {
+		/* Ignore "No such adapter" errors; just means bluetooth isn't active */
+		if (   !dbus_g_error_has_name (err, "org.bluez.Error.NoSuchAdapter")
+		    && !dbus_g_error_has_name (err, "org.freedesktop.systemd1.LoadFailed")
+		    && !g_error_matches (err, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN)) {
+			nm_log_warn (LOGD_BT, "bluez error getting default adapter: %s",
+			             err && err->message ? err->message : "(unknown)");
+		}
+		g_error_free (err);
+		return;
+	}
+
+	default_adapter_changed (priv->proxy, default_adapter, self);
+}
+
+static void
+query_default_adapter (NMBluezManager *self)
+{
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+	DBusGProxyCall *call;
+
+	call = dbus_g_proxy_begin_call (priv->proxy, "DefaultAdapter",
+	                                default_adapter_cb,
+	                                self,
+	                                NULL, G_TYPE_INVALID);
+	if (!call)
+		nm_log_warn (LOGD_BT, "failed to request default Bluetooth adapter.");
+}
+
+static void
+bluez_connect (NMBluezManager *self)
+{
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+	DBusGConnection *connection;
+
+	g_return_if_fail (priv->proxy == NULL);
+
+	connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
+	if (!connection)
+		return;
+
+	priv->proxy = dbus_g_proxy_new_for_name (connection,
+	                                         BLUEZ_SERVICE,
+	                                         BLUEZ_MANAGER_PATH,
+	                                         BLUEZ_MANAGER_INTERFACE);
+
+	dbus_g_proxy_add_signal (priv->proxy, "AdapterRemoved",
+	                         DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->proxy, "AdapterRemoved",
+	                             G_CALLBACK (adapter_removed), self, NULL);
+
+	dbus_g_proxy_add_signal (priv->proxy, "DefaultAdapterChanged",
+	                         DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->proxy, "DefaultAdapterChanged",
+	                             G_CALLBACK (default_adapter_changed), self, NULL);
+
+	query_default_adapter (self);
+}
+
+static void
+name_owner_changed_cb (NMDBusManager *dbus_mgr,
+                       const char *name,
+                       const char *old_owner,
+                       const char *new_owner,
+                       gpointer user_data)
+{
+	NMBluezManager *self = NM_BLUEZ_MANAGER (user_data);
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+	gboolean old_owner_good = (old_owner && strlen (old_owner));
+	gboolean new_owner_good = (new_owner && strlen (new_owner));
+
+	/* Can't handle the signal if its not from the Bluez */
+	if (strcmp (BLUEZ_SERVICE, name))
+		return;
+
+	if (!old_owner_good && new_owner_good)
+		query_default_adapter (self);
+	else if (old_owner_good && !new_owner_good) {
+		/* Throwing away the adapter removes all devices too */
+		if (priv->adapter) {
+			g_object_unref (priv->adapter);
+			priv->adapter = NULL;
+		}
+	}
+}
+
+static void
+bluez_cleanup (NMBluezManager *self, gboolean do_signal)
+{
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+
+	if (priv->proxy) {
+		g_object_unref (priv->proxy);
+		priv->proxy = NULL;
+	}
+
+	if (priv->adapter) {
+		g_object_unref (priv->adapter);
+		priv->adapter = NULL;
+	}
+}
+
+static void
+dbus_connection_changed_cb (NMDBusManager *dbus_mgr,
+                            DBusGConnection *connection,
+                            gpointer user_data)
+{
+	NMBluezManager *self = NM_BLUEZ_MANAGER (user_data);
+
+	if (!connection)
+		bluez_cleanup (self, TRUE);
+	else
+		bluez_connect (self);
+}
+
+/****************************************************************/
+
+NMBluezManager *
+nm_bluez_manager_get (NMConnectionProvider *provider)
+{
+	static NMBluezManager *singleton = NULL;
+
+	if (singleton)
+		return g_object_ref (singleton);
+
+	singleton = (NMBluezManager *) g_object_new (NM_TYPE_BLUEZ_MANAGER, NULL);
+	g_assert (singleton);
+
+	/* Cache the connection provider for NMBluezAdapter objects */
+	NM_BLUEZ_MANAGER_GET_PRIVATE (singleton)->provider = provider;
+
+	return singleton;
+}
+
+static void
+nm_bluez_manager_init (NMBluezManager *self)
+{
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+
+	priv->dbus_mgr = nm_dbus_manager_get ();
+	g_assert (priv->dbus_mgr);
+
+	g_signal_connect (priv->dbus_mgr,
+	                  NM_DBUS_MANAGER_NAME_OWNER_CHANGED,
+	                  G_CALLBACK (name_owner_changed_cb),
+	                  self);
+
+	g_signal_connect (priv->dbus_mgr,
+	                  NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED,
+	                  G_CALLBACK (dbus_connection_changed_cb),
+	                  self);
+
+	bluez_connect (self);
+}
+
+static void
+dispose (GObject *object)
+{
+	NMBluezManager *self = NM_BLUEZ_MANAGER (object);
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
+
+	bluez_cleanup (self, FALSE);
+
+	if (priv->dbus_mgr) {
+		g_signal_handlers_disconnect_by_func (priv->dbus_mgr, name_owner_changed_cb, self);
+		g_signal_handlers_disconnect_by_func (priv->dbus_mgr, dbus_connection_changed_cb, self);
+		g_object_unref (priv->dbus_mgr);
+	}
+
+	G_OBJECT_CLASS (nm_bluez_manager_parent_class)->dispose (object);
+}
+
+static void
+nm_bluez_manager_class_init (NMBluezManagerClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (NMBluezManagerPrivate));
+
+	/* virtual methods */
+	object_class->dispose = dispose;
+
+	/* Signals */
+	signals[BDADDR_ADDED] =
+		g_signal_new (NM_BLUEZ_MANAGER_BDADDR_ADDED,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMBluezManagerClass, bdaddr_added),
+		              NULL, NULL, NULL,
+		              G_TYPE_NONE, 5, G_TYPE_OBJECT, G_TYPE_STRING,
+		              G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT);
+
+	signals[BDADDR_REMOVED] =
+		g_signal_new (NM_BLUEZ_MANAGER_BDADDR_REMOVED,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMBluezManagerClass, bdaddr_removed),
+		              NULL, NULL, NULL,
+		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
+}
+