summary refs log tree commit diff
path: root/src/modem-manager
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2013-02-03 14:49:22 +0100
committerMichael Biebl <biebl@debian.org>2013-02-03 14:49:22 +0100
commit9c202e3e860b3be9e1f8882630b69affbb130102 (patch)
tree8202bf39f2129486971fa7d5ae0dee61a561aa53 /src/modem-manager
parent36cb2f364a821e1be50b23e03a18891ec55adb06 (diff)
Imported Upstream version 0.9.7.995 upstream/0.9.7.995
Diffstat (limited to 'src/modem-manager')
-rw-r--r--src/modem-manager/Makefile.am10
-rw-r--r--src/modem-manager/Makefile.in146
-rw-r--r--src/modem-manager/README45
-rw-r--r--src/modem-manager/nm-modem-broadband.c1033
-rw-r--r--src/modem-manager/nm-modem-broadband.h69
-rw-r--r--src/modem-manager/nm-modem-cdma.c77
-rw-r--r--src/modem-manager/nm-modem-cdma.h21
-rw-r--r--src/modem-manager/nm-modem-generic.c445
-rw-r--r--src/modem-manager/nm-modem-generic.h69
-rw-r--r--src/modem-manager/nm-modem-gsm.c99
-rw-r--r--src/modem-manager/nm-modem-gsm.h23
-rw-r--r--src/modem-manager/nm-modem-manager.c451
-rw-r--r--src/modem-manager/nm-modem-manager.h13
-rw-r--r--src/modem-manager/nm-modem-types.h39
-rw-r--r--src/modem-manager/nm-modem.c629
-rw-r--r--src/modem-manager/nm-modem.h59
16 files changed, 2529 insertions, 699 deletions
diff --git a/src/modem-manager/Makefile.am b/src/modem-manager/Makefile.am
index b9cc7644..aa5534fc 100644
--- a/src/modem-manager/Makefile.am
+++ b/src/modem-manager/Makefile.am
@@ -15,6 +15,8 @@ noinst_LTLIBRARIES = libmodem-manager.la
 libmodem_manager_la_SOURCES = \
 	nm-modem.c \
 	nm-modem.h \
+	nm-modem-generic.c \
+	nm-modem-generic.h \
 	nm-modem-cdma.c \
 	nm-modem-cdma.h \
 	nm-modem-gsm.c \
@@ -33,3 +35,11 @@ libmodem_manager_la_LIBADD = \
 	$(LIBNL_LIBS) \
 	$(DBUS_LIBS)
 
+# Support for the new ModemManager1 interface
+if WITH_MODEM_MANAGER_1
+libmodem_manager_la_SOURCES += \
+	nm-modem-broadband.h \
+	nm-modem-broadband.c
+libmodem_manager_la_CPPFLAGS += $(MM_GLIB_CFLAGS)
+libmodem_manager_la_LIBADD += $(MM_GLIB_LIBS)
+endif
diff --git a/src/modem-manager/Makefile.in b/src/modem-manager/Makefile.in
index 6da50ed0..0546ee2e 100644
--- a/src/modem-manager/Makefile.in
+++ b/src/modem-manager/Makefile.in
@@ -51,20 +51,30 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
+
+# Support for the new ModemManager1 interface
+@WITH_MODEM_MANAGER_1_TRUE@am__append_1 = \
+@WITH_MODEM_MANAGER_1_TRUE@	nm-modem-broadband.h \
+@WITH_MODEM_MANAGER_1_TRUE@	nm-modem-broadband.c
+
+@WITH_MODEM_MANAGER_1_TRUE@am__append_2 = $(MM_GLIB_CFLAGS)
+@WITH_MODEM_MANAGER_1_TRUE@am__append_3 = $(MM_GLIB_LIBS)
 subdir = src/modem-manager
-DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
-	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gtk-doc.m4 \
-	$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
-	$(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/introspection.m4 \
-	$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
-	$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libnl-check.m4 \
-	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
-	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
-	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
-	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
-	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gnome-code-coverage.m4 \
+	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
+	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
+	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
+	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
+	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
+	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -73,14 +83,23 @@ CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
+@WITH_MODEM_MANAGER_1_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
 libmodem_manager_la_DEPENDENCIES =  \
 	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
-	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_2)
+am__libmodem_manager_la_SOURCES_DIST = nm-modem.c nm-modem.h \
+	nm-modem-generic.c nm-modem-generic.h nm-modem-cdma.c \
+	nm-modem-cdma.h nm-modem-gsm.c nm-modem-gsm.h \
+	nm-modem-manager.h nm-modem-manager.c nm-modem-types.h \
+	nm-modem-broadband.h nm-modem-broadband.c
+@WITH_MODEM_MANAGER_1_TRUE@am__objects_1 = libmodem_manager_la-nm-modem-broadband.lo
 am_libmodem_manager_la_OBJECTS = libmodem_manager_la-nm-modem.lo \
+	libmodem_manager_la-nm-modem-generic.lo \
 	libmodem_manager_la-nm-modem-cdma.lo \
 	libmodem_manager_la-nm-modem-gsm.lo \
-	libmodem_manager_la-nm-modem-manager.lo
+	libmodem_manager_la-nm-modem-manager.lo $(am__objects_1)
 libmodem_manager_la_OBJECTS = $(am_libmodem_manager_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -112,7 +131,7 @@ AM_V_GEN = $(am__v_GEN_@AM_V@)
 am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
 am__v_GEN_0 = @echo "  GEN   " $@;
 SOURCES = $(libmodem_manager_la_SOURCES)
-DIST_SOURCES = $(libmodem_manager_la_SOURCES)
+DIST_SOURCES = $(am__libmodem_manager_la_SOURCES_DIST)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -133,6 +152,10 @@ AWK = @AWK@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
+CKDB_PATH = @CKDB_PATH@
+CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
 CXX = @CXX@
@@ -147,9 +170,7 @@ DBUS_SYS_DIR = @DBUS_SYS_DIR@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DHCLIENT_PATH = @DHCLIENT_PATH@
-DHCLIENT_VERSION = @DHCLIENT_VERSION@
 DHCPCD_PATH = @DHCPCD_PATH@
-DISABLE_DEPRECATED = @DISABLE_DEPRECATED@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -159,17 +180,14 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 FGREP = @FGREP@
+GENHTML = @GENHTML@
 GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
 GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
-GIO_CFLAGS = @GIO_CFLAGS@
-GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
 GLIB_MAKEFILE = @GLIB_MAKEFILE@
 GLIB_MKENUMS = @GLIB_MKENUMS@
-GMODULE_CFLAGS = @GMODULE_CFLAGS@
-GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
 GMSGFMT_015 = @GMSGFMT_015@
 GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
@@ -210,6 +228,7 @@ IPTABLES_PATH = @IPTABLES_PATH@
 IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
 IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
 KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
+LCOV = @LCOV@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
 LIBDL = @LIBDL@
@@ -226,11 +245,7 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
-LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
-LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
-LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
-LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
@@ -245,6 +260,8 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MM_GLIB_CFLAGS = @MM_GLIB_CFLAGS@
+MM_GLIB_LIBS = @MM_GLIB_LIBS@
 MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
@@ -254,6 +271,7 @@ NMEDIT = @NMEDIT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
 NM_MICRO_VERSION = @NM_MICRO_VERSION@
 NM_MINOR_VERSION = @NM_MINOR_VERSION@
+NM_MODIFY_SYSTEM_POLICY = @NM_MODIFY_SYSTEM_POLICY@
 NM_VERSION = @NM_VERSION@
 NSS_CFLAGS = @NSS_CFLAGS@
 NSS_LIBS = @NSS_LIBS@
@@ -280,13 +298,14 @@ PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
 QT_CFLAGS = @QT_CFLAGS@
 QT_LIBS = @QT_LIBS@
 RANLIB = @RANLIB@
-RESOLVCONF_PATH = @RESOLVCONF_PATH@
 SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
-SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
-SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_INHIBIT_CFLAGS = @SYSTEMD_INHIBIT_CFLAGS@
+SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@
+SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@
+SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -341,6 +360,11 @@ localedir = @localedir@
 localstatedir = @localstatedir@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
+nmbinary = @nmbinary@
+nmconfdir = @nmconfdir@
+nmdatadir = @nmdatadir@
+nmrundir = @nmrundir@
+nmstatedir = @nmstatedir@
 oldincludedir = @oldincludedir@
 pdfdir = @pdfdir@
 prefix = @prefix@
@@ -355,6 +379,10 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
+with_dhclient = @with_dhclient@
+with_dhcpcd = @with_dhcpcd@
+with_netconfig = @with_netconfig@
+with_resolvconf = @with_resolvconf@
 INCLUDES = \
 	-I${top_srcdir}/src \
 	-I${top_builddir}/src/generated \
@@ -366,27 +394,16 @@ INCLUDES = \
 	-I${top_srcdir}/libnm-util
 
 noinst_LTLIBRARIES = libmodem-manager.la
-libmodem_manager_la_SOURCES = \
-	nm-modem.c \
-	nm-modem.h \
-	nm-modem-cdma.c \
-	nm-modem-cdma.h \
-	nm-modem-gsm.c \
-	nm-modem-gsm.h \
-	nm-modem-manager.h \
-	nm-modem-manager.c \
-	nm-modem-types.h
-
-libmodem_manager_la_CPPFLAGS = \
-	$(LIBNL_CFLAGS) \
-	$(DBUS_CFLAGS)
-
-libmodem_manager_la_LIBADD = \
+libmodem_manager_la_SOURCES = nm-modem.c nm-modem.h nm-modem-generic.c \
+	nm-modem-generic.h nm-modem-cdma.c nm-modem-cdma.h \
+	nm-modem-gsm.c nm-modem-gsm.h nm-modem-manager.h \
+	nm-modem-manager.c nm-modem-types.h $(am__append_1)
+libmodem_manager_la_CPPFLAGS = $(LIBNL_CFLAGS) $(DBUS_CFLAGS) \
+	$(am__append_2)
+libmodem_manager_la_LIBADD =  \
 	$(top_builddir)/src/generated/libnm-generated.la \
-	$(top_builddir)/src/logging/libnm-logging.la \
-	$(LIBNL_LIBS) \
-	$(DBUS_LIBS)
-
+	$(top_builddir)/src/logging/libnm-logging.la $(LIBNL_LIBS) \
+	$(DBUS_LIBS) $(am__append_3)
 all: all-am
 
 .SUFFIXES:
@@ -439,31 +456,30 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmodem_manager_la-nm-modem-broadband.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmodem_manager_la-nm-modem-cdma.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmodem_manager_la-nm-modem-generic.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmodem_manager_la-nm-modem-gsm.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmodem_manager_la-nm-modem-manager.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmodem_manager_la-nm-modem.Plo@am__quote@
 
 .c.o:
-@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
-@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
-@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
 
 .c.obj:
-@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
-@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
-@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
 
 .c.lo:
-@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
-@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
-@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
@@ -475,6 +491,13 @@ libmodem_manager_la-nm-modem.lo: nm-modem.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) $(libmodem_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmodem_manager_la-nm-modem.lo `test -f 'nm-modem.c' || echo '$(srcdir)/'`nm-modem.c
 
+libmodem_manager_la-nm-modem-generic.lo: nm-modem-generic.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmodem_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmodem_manager_la-nm-modem-generic.lo -MD -MP -MF $(DEPDIR)/libmodem_manager_la-nm-modem-generic.Tpo -c -o libmodem_manager_la-nm-modem-generic.lo `test -f 'nm-modem-generic.c' || echo '$(srcdir)/'`nm-modem-generic.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libmodem_manager_la-nm-modem-generic.Tpo $(DEPDIR)/libmodem_manager_la-nm-modem-generic.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-modem-generic.c' object='libmodem_manager_la-nm-modem-generic.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) $(libmodem_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmodem_manager_la-nm-modem-generic.lo `test -f 'nm-modem-generic.c' || echo '$(srcdir)/'`nm-modem-generic.c
+
 libmodem_manager_la-nm-modem-cdma.lo: nm-modem-cdma.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmodem_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmodem_manager_la-nm-modem-cdma.lo -MD -MP -MF $(DEPDIR)/libmodem_manager_la-nm-modem-cdma.Tpo -c -o libmodem_manager_la-nm-modem-cdma.lo `test -f 'nm-modem-cdma.c' || echo '$(srcdir)/'`nm-modem-cdma.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libmodem_manager_la-nm-modem-cdma.Tpo $(DEPDIR)/libmodem_manager_la-nm-modem-cdma.Plo
@@ -496,6 +519,13 @@ libmodem_manager_la-nm-modem-manager.lo: nm-modem-manager.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) $(libmodem_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmodem_manager_la-nm-modem-manager.lo `test -f 'nm-modem-manager.c' || echo '$(srcdir)/'`nm-modem-manager.c
 
+libmodem_manager_la-nm-modem-broadband.lo: nm-modem-broadband.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmodem_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmodem_manager_la-nm-modem-broadband.lo -MD -MP -MF $(DEPDIR)/libmodem_manager_la-nm-modem-broadband.Tpo -c -o libmodem_manager_la-nm-modem-broadband.lo `test -f 'nm-modem-broadband.c' || echo '$(srcdir)/'`nm-modem-broadband.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libmodem_manager_la-nm-modem-broadband.Tpo $(DEPDIR)/libmodem_manager_la-nm-modem-broadband.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-modem-broadband.c' object='libmodem_manager_la-nm-modem-broadband.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) $(libmodem_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmodem_manager_la-nm-modem-broadband.lo `test -f 'nm-modem-broadband.c' || echo '$(srcdir)/'`nm-modem-broadband.c
+
 mostlyclean-libtool:
 	-rm -f *.lo
 
diff --git a/src/modem-manager/README b/src/modem-manager/README
new file mode 100644
index 00000000..c9f0f5f1
--- /dev/null
+++ b/src/modem-manager/README
@@ -0,0 +1,45 @@
+
+ModemManager integration is organized as follows:
+
+
+Common source
+********************************************************************************
+
+ * nm-modem.[h|c]:
+      Defines the basic `NMModem' object. The core NetworkManager implementation
+      will use this interface exclusively, regardless of the real final type of
+      the modem object.
+
+ * nm-modem-manager.[h|c]:
+      Defines the `NMModemManager' object, which takes care of listening to
+      signals from the DBus inteface notifying about added or removed modems.
+      It also takes care of creating proper `NMModem' objects from the
+      information retrieved from the DBus interface.
+
+
+ModemManager 0.7 integration
+********************************************************************************
+
+ * nm-modem-broadband.[h|c]:
+      Defines the `NMModemBroadband' object, which is a subclass of `NMModem'.
+      This object handles both 3GPP and 3GPP2 modems exposed in the new
+      `ModemManager1' interface.
+
+
+ModemManager 0.4/0.5/0.6 integration
+********************************************************************************
+
+ * nm-modem-types.h:
+      Defines helper types to use with the (old) ModemManager DBus API.
+
+ * nm-modem-generic.[h|c]:
+      Defines the `NMModemGeneric' object. All modem objects based on the old
+      ModemManager interface are subclasses of this one.
+
+ * nm-modem-gsm.[h|c]:
+      Defines the `NMModemGsm' object, which is a subclass of `NMModemGeneric'.
+      This object handles 3GPP-specific (GSM, UMTS, HSPA, LTE) modems.
+
+ * nm-modem-cdma.[h|c]:
+      Defines the `NMModemCdma' object, which is a subclass of `NMModemGeneric'.
+      This object handles 3GPP2-specific modems (CDMA, EV-DO).
diff --git a/src/modem-manager/nm-modem-broadband.c b/src/modem-manager/nm-modem-broadband.c
new file mode 100644
index 00000000..05cd3565
--- /dev/null
+++ b/src/modem-manager/nm-modem-broadband.c
@@ -0,0 +1,1033 @@
+/* -*- 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) 2012 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <glib/gi18n.h>
+#include <string.h>
+#include <libmm-glib.h>
+#include "nm-modem-broadband.h"
+#include "nm-system.h"
+#include "nm-setting-connection.h"
+#include "nm-logging.h"
+#include "NetworkManagerUtils.h"
+#include "nm-device-private.h"
+
+G_DEFINE_TYPE (NMModemBroadband, nm_modem_broadband, NM_TYPE_MODEM)
+
+struct _NMModemBroadbandPrivate {
+	/* The modem object from dbus */
+	MMObject *modem_object;
+	/* Per-interface objects */
+	MMModem *modem_iface;
+	MMModemSimple *simple_iface;
+
+	/* Connection setup */
+	MMSimpleConnectProperties *connect_properties;
+	MMBearer *bearer;
+	MMBearerIpConfig *ipv4_config;
+	MMBearerIpConfig *ipv6_config;
+
+	guint32 pin_tries;
+};
+
+enum {
+	PROP_0,
+	PROP_MODEM,
+};
+
+#define MODEM_CAPS_3GPP(caps) (caps & (MM_MODEM_CAPABILITY_GSM_UMTS |    \
+                                       MM_MODEM_CAPABILITY_LTE |         \
+                                       MM_MODEM_CAPABILITY_LTE_ADVANCED))
+
+#define MODEM_CAPS_3GPP2(caps) (caps & (MM_MODEM_CAPABILITY_CDMA_EVDO))
+
+/*****************************************************************************/
+
+#define NM_MODEM_BROADBAND_ERROR (nm_modem_broadband_error_quark ())
+
+static GQuark
+nm_modem_broadband_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("nm-modem-broadband-error");
+	return quark;
+}
+
+static NMDeviceStateReason
+translate_mm_error (GError *error)
+{
+	NMDeviceStateReason reason;
+
+	if (g_error_matches (error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_CARRIER))
+		reason = NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER;
+	else if (g_error_matches (error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_DIALTONE))
+		reason = NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE;
+	else if (g_error_matches (error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_BUSY))
+		reason = NM_DEVICE_STATE_REASON_MODEM_BUSY;
+	else if (g_error_matches (error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_ANSWER))
+		reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT;
+	else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NETWORK_NOT_ALLOWED))
+		reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED;
+	else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT))
+		reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT;
+	else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NO_NETWORK))
+		reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING;
+	else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED))
+		reason = NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED;
+	else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN))
+		reason = NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED;
+	else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK))
+		reason = NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED;
+	else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG))
+		reason = NM_DEVICE_STATE_REASON_GSM_SIM_WRONG;
+	else {
+		/* unable to map the ModemManager error to a NM_DEVICE_STATE_REASON */
+		nm_log_dbg (LOGD_MB, "unmapped error detected: '%s'", error->message);
+		reason = NM_DEVICE_STATE_REASON_UNKNOWN;
+	}
+
+	return reason;
+}
+
+/*****************************************************************************/
+
+void
+nm_modem_broadband_get_capabilities (NMModemBroadband *self,
+                                     NMDeviceModemCapabilities *modem_caps,
+                                     NMDeviceModemCapabilities *current_caps)
+{
+	*modem_caps = (NMDeviceModemCapabilities)mm_modem_get_modem_capabilities (self->priv->modem_iface);
+	*current_caps = (NMDeviceModemCapabilities)mm_modem_get_current_capabilities (self->priv->modem_iface);
+}
+
+/*****************************************************************************/
+
+static void
+ask_for_pin (NMModemBroadband *self)
+{
+	guint32 tries;
+
+	tries = self->priv->pin_tries++;
+	nm_modem_get_secrets (NM_MODEM (self),
+	                      NM_SETTING_GSM_SETTING_NAME,
+	                      tries ? TRUE : FALSE,
+	                      NM_SETTING_GSM_PIN);
+}
+
+static void
+connect_ready (MMModemSimple *simple_iface,
+               GAsyncResult *res,
+               NMModemBroadband *self)
+{
+	GError *error = NULL;
+	guint ip_method;
+
+	g_clear_object (&self->priv->connect_properties);
+
+	self->priv->bearer = mm_modem_simple_connect_finish (simple_iface, res, &error);
+	if (!self->priv->bearer) {
+		if (g_error_matches (error,
+		                     MM_MOBILE_EQUIPMENT_ERROR,
+		                     MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) ||
+			(g_error_matches (error,
+		                          MM_CORE_ERROR,
+		                          MM_CORE_ERROR_UNAUTHORIZED) &&
+			 mm_modem_get_unlock_required (self->priv->modem_iface) == MM_MODEM_LOCK_SIM_PIN)) {
+			/* Request PIN */
+			ask_for_pin (self);
+		} else {
+			/* Strip remote error info before logging it */
+			if (g_dbus_error_is_remote_error (error))
+				g_dbus_error_strip_remote_error (error);
+
+			nm_log_warn (LOGD_MB, "(%s) failed to connect modem: %s",
+			             nm_modem_get_uid (NM_MODEM (self)),
+			             error && error->message ? error->message : "(unknown)");
+			g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (error));
+		}
+
+		g_clear_error (&error);
+		g_object_unref (self);
+		return;
+	}
+
+	/* Grab IP configurations */
+	self->priv->ipv4_config = mm_bearer_get_ipv4_config (self->priv->bearer);
+	self->priv->ipv6_config = mm_bearer_get_ipv6_config (self->priv->bearer);
+
+	switch (mm_bearer_ip_config_get_method (self->priv->ipv4_config)) {
+	case MM_BEARER_IP_METHOD_PPP:
+		ip_method = MM_MODEM_IP_METHOD_PPP;
+		break;
+	case MM_BEARER_IP_METHOD_STATIC:
+		ip_method = MM_MODEM_IP_METHOD_STATIC;
+		break;
+	case MM_BEARER_IP_METHOD_DHCP:
+		ip_method = MM_MODEM_IP_METHOD_DHCP;
+		break;
+	default:
+		error = g_error_new (NM_MODEM_BROADBAND_ERROR,
+		                     NM_MODEM_BROADBAND_ERROR_CONNECTION_INVALID,
+		                     "invalid IP config");
+		nm_log_warn (LOGD_MB, "(%s) failed to connect modem: %s",
+		             nm_modem_get_uid (NM_MODEM (self)),
+		             error->message);
+		g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (error));
+		g_error_free (error);
+		g_object_unref (self);
+		return;
+	}
+
+	/* IPv4 for now only */
+	g_object_set (self,
+	              NM_MODEM_DATA_PORT,  mm_bearer_get_interface (self->priv->bearer),
+	              NM_MODEM_IP_METHOD,  ip_method,
+	              NM_MODEM_IP_TIMEOUT, mm_bearer_get_ip_timeout (self->priv->bearer),
+	              NULL);
+
+	g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, TRUE, NM_DEVICE_STATE_REASON_NONE);
+	g_object_unref (self);
+}
+
+static MMSimpleConnectProperties *
+create_cdma_connect_properties (NMConnection *connection)
+{
+	NMSettingCdma *setting;
+	MMSimpleConnectProperties *properties;
+	const gchar *str;
+
+	setting = nm_connection_get_setting_cdma (connection);
+	properties = mm_simple_connect_properties_new ();
+
+	str = nm_setting_cdma_get_number (setting);
+	if (str)
+		mm_simple_connect_properties_set_number (properties, str);
+
+	return properties;
+}
+
+static MMSimpleConnectProperties *
+create_gsm_connect_properties (NMConnection *connection)
+{
+	NMSettingGsm *setting;
+	NMSettingPPP *s_ppp;
+	MMSimpleConnectProperties *properties;
+	const gchar *str;
+
+	setting = nm_connection_get_setting_gsm (connection);
+	properties = mm_simple_connect_properties_new ();
+
+	/* TODO: not needed */
+	str = nm_setting_gsm_get_number (setting);
+	if (str)
+		mm_simple_connect_properties_set_number (properties, str);
+
+	str = nm_setting_gsm_get_apn (setting);
+	if (str)
+		mm_simple_connect_properties_set_apn (properties, str);
+
+	str = nm_setting_gsm_get_network_id (setting);
+	if (str)
+		mm_simple_connect_properties_set_operator_id (properties, str);
+
+	str = nm_setting_gsm_get_pin (setting);
+	if (str)
+		mm_simple_connect_properties_set_pin (properties, str);
+
+	str = nm_setting_gsm_get_username (setting);
+	if (str)
+		mm_simple_connect_properties_set_user (properties, str);
+
+	str = nm_setting_gsm_get_password (setting);
+	if (str)
+		mm_simple_connect_properties_set_password (properties, str);
+
+	/* TODO: We should check SUPPORTED MODES here */
+	switch (nm_setting_gsm_get_network_type (setting)) {
+	case NM_SETTING_GSM_NETWORK_TYPE_UMTS_HSPA:
+		mm_simple_connect_properties_set_allowed_modes (properties,
+		                                                MM_MODEM_MODE_3G,
+		                                                MM_MODEM_MODE_NONE);
+		break;
+	case NM_SETTING_GSM_NETWORK_TYPE_GPRS_EDGE:
+		mm_simple_connect_properties_set_allowed_modes (properties,
+		                                                MM_MODEM_MODE_2G,
+		                                                MM_MODEM_MODE_NONE);
+		break;
+	case NM_SETTING_GSM_NETWORK_TYPE_PREFER_UMTS_HSPA:
+		mm_simple_connect_properties_set_allowed_modes (properties,
+		                                                MM_MODEM_MODE_ANY,
+		                                                MM_MODEM_MODE_3G);
+		break;
+	case NM_SETTING_GSM_NETWORK_TYPE_PREFER_GPRS_EDGE:
+		mm_simple_connect_properties_set_allowed_modes (properties,
+		                                                MM_MODEM_MODE_ANY,
+		                                                MM_MODEM_MODE_2G);
+		break;
+	case NM_SETTING_GSM_NETWORK_TYPE_PREFER_4G:
+		mm_simple_connect_properties_set_allowed_modes (properties,
+		                                                MM_MODEM_MODE_ANY,
+		                                                MM_MODEM_MODE_4G);
+		break;
+	case NM_SETTING_GSM_NETWORK_TYPE_4G:
+		mm_simple_connect_properties_set_allowed_modes (properties,
+		                                                MM_MODEM_MODE_4G,
+		                                                MM_MODEM_MODE_NONE);
+		break;
+	default:
+		mm_simple_connect_properties_set_allowed_modes (properties,
+		                                                MM_MODEM_MODE_ANY,
+		                                                MM_MODEM_MODE_NONE);
+		break;
+	}
+
+	/* Roaming */
+	if (nm_setting_gsm_get_home_only (setting))
+		mm_simple_connect_properties_set_allow_roaming (properties, FALSE);
+
+	/* For IpMethod == STATIC or DHCP */
+	s_ppp = nm_connection_get_setting_ppp (connection);
+	if (s_ppp) {
+		MMBearerAllowedAuth allowed_auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN;
+
+		if (nm_setting_ppp_get_noauth (s_ppp))
+			allowed_auth = MM_BEARER_ALLOWED_AUTH_NONE;
+		if (!nm_setting_ppp_get_refuse_pap (s_ppp))
+			allowed_auth |= MM_BEARER_ALLOWED_AUTH_PAP;
+		if (!nm_setting_ppp_get_refuse_chap (s_ppp))
+			allowed_auth |= MM_BEARER_ALLOWED_AUTH_CHAP;
+		if (!nm_setting_ppp_get_refuse_mschap (s_ppp))
+			allowed_auth |= MM_BEARER_ALLOWED_AUTH_MSCHAP;
+		if (!nm_setting_ppp_get_refuse_mschapv2 (s_ppp))
+			allowed_auth |= MM_BEARER_ALLOWED_AUTH_MSCHAPV2;
+		if (!nm_setting_ppp_get_refuse_eap (s_ppp))
+			allowed_auth |= MM_BEARER_ALLOWED_AUTH_EAP;
+
+		mm_simple_connect_properties_set_allowed_auth (properties, allowed_auth);
+	}
+
+	return properties;
+}
+
+static NMActStageReturn
+act_stage1_prepare (NMModem *_self,
+                    NMActRequest *req,
+                    GPtrArray **out_hints,
+                    const char **out_setting_name,
+                    NMDeviceStateReason *reason)
+{
+	NMModemBroadband *self = NM_MODEM_BROADBAND (_self);
+	NMConnection *connection;
+
+	connection = nm_act_request_get_connection (req);
+	g_assert (connection);
+
+	*out_setting_name = nm_connection_need_secrets (connection, out_hints);
+	if (!*out_setting_name) {
+		MMModemCapability caps;
+
+		caps = mm_modem_get_current_capabilities (self->priv->modem_iface);
+
+		g_clear_object (&self->priv->connect_properties);
+
+		if (MODEM_CAPS_3GPP (caps))
+			self->priv->connect_properties = create_gsm_connect_properties (connection);
+		else if (MODEM_CAPS_3GPP2 (caps))
+			self->priv->connect_properties = create_cdma_connect_properties (connection);
+		else {
+			nm_log_warn (LOGD_MB, "(%s) not a mobile broadband modem",
+						 nm_modem_get_uid (NM_MODEM (self)));
+			return NM_ACT_STAGE_RETURN_FAILURE;
+		}
+
+		if (!self->priv->simple_iface)
+			self->priv->simple_iface = mm_object_get_modem_simple (self->priv->modem_object);
+
+		mm_modem_simple_connect (self->priv->simple_iface,
+		                         self->priv->connect_properties,
+		                         NULL,
+		                         (GAsyncReadyCallback)connect_ready,
+		                         g_object_ref (self));
+	} else {
+		/* NMModem will handle requesting secrets... */
+	}
+
+	return NM_ACT_STAGE_RETURN_POSTPONE;
+}
+
+/*****************************************************************************/
+
+static NMConnection *
+get_best_auto_connection (NMModem *_self,
+                          GSList *connections,
+                          char **specific_object)
+{
+	NMModemBroadband *self = NM_MODEM_BROADBAND (_self);
+	MMModemCapability modem_caps;
+	GSList *iter;
+
+	modem_caps = mm_modem_get_current_capabilities (self->priv->modem_iface);
+
+	for (iter = connections; iter; iter = g_slist_next (iter)) {
+		NMConnection *connection = NM_CONNECTION (iter->data);
+		NMSettingConnection *s_con;
+
+		s_con = nm_connection_get_setting_connection (connection);
+		g_assert (s_con);
+
+		if (!nm_setting_connection_get_autoconnect (s_con))
+			continue;
+
+		/* If GSM settings given and our modem is 3GPP, those are the best ones */
+		if (   g_str_equal (nm_setting_connection_get_connection_type (s_con),
+		                    NM_SETTING_GSM_SETTING_NAME)
+		    && MODEM_CAPS_3GPP (modem_caps))
+			return connection;
+
+		/* If CDMA settings given and our modem is 3GPP2, return those */
+		if (   g_str_equal (nm_setting_connection_get_connection_type (s_con),
+		                    NM_SETTING_CDMA_SETTING_NAME)
+		    && MODEM_CAPS_3GPP2 (modem_caps))
+			return connection;
+
+		/* continue */
+	}
+
+	return NULL;
+}
+
+/*****************************************************************************/
+
+static gboolean
+check_connection_compatible (NMModem *_self,
+                             NMConnection *connection,
+                             GError **error)
+{
+	NMModemBroadband *self = NM_MODEM_BROADBAND (_self);
+	MMModemCapability modem_caps;
+	NMSettingConnection *s_con;
+
+	modem_caps = mm_modem_get_current_capabilities (self->priv->modem_iface);
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+
+	if (MODEM_CAPS_3GPP (modem_caps)) {
+		NMSettingGsm *s_gsm;
+
+		if (!g_str_equal (nm_setting_connection_get_connection_type (s_con),
+		                  NM_SETTING_GSM_SETTING_NAME)) {
+			g_set_error (error,
+			             NM_MODEM_BROADBAND_ERROR,
+			             NM_MODEM_BROADBAND_ERROR_CONNECTION_NOT_GSM,
+			             "The connection was not a 3GPP connection.");
+			return FALSE;
+		}
+
+		s_gsm = nm_connection_get_setting_gsm (connection);
+		if (!s_gsm) {
+			g_set_error (error,
+			             NM_MODEM_BROADBAND_ERROR,
+			             NM_MODEM_BROADBAND_ERROR_CONNECTION_INVALID,
+			             "The connection was not a valid 3GPP connection.");
+			return FALSE;
+		}
+
+		return TRUE;
+	}
+
+	if (MODEM_CAPS_3GPP2 (modem_caps)) {
+		NMSettingCdma *s_cdma;
+
+		if (!g_str_equal (nm_setting_connection_get_connection_type (s_con),
+		                  NM_SETTING_CDMA_SETTING_NAME)) {
+			g_set_error (error,
+			             NM_MODEM_BROADBAND_ERROR,
+			             NM_MODEM_BROADBAND_ERROR_CONNECTION_NOT_CDMA,
+			             "The connection was not a 3GPP2 connection.");
+			return FALSE;
+		}
+
+		s_cdma = nm_connection_get_setting_cdma (connection);
+		if (!s_cdma) {
+			g_set_error (error,
+			             NM_MODEM_BROADBAND_ERROR,
+			             NM_MODEM_BROADBAND_ERROR_CONNECTION_INVALID,
+			             "The connection was not a valid 3GPP2 connection.");
+			return FALSE;
+		}
+
+		return TRUE;
+	}
+
+	g_set_error (error,
+	             NM_MODEM_BROADBAND_ERROR,
+	             NM_MODEM_BROADBAND_ERROR_CONNECTION_INCOMPATIBLE,
+	             "Device is not a mobile broadband modem");
+	return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+complete_connection (NMModem *_self,
+                     NMConnection *connection,
+                     const GSList *existing_connections,
+                     GError **error)
+{
+	NMModemBroadband *self = NM_MODEM_BROADBAND (_self);
+	MMModemCapability modem_caps;
+	NMSettingPPP *s_ppp;
+
+	modem_caps = mm_modem_get_current_capabilities (self->priv->modem_iface);
+
+	/* PPP settings common to 3GPP and 3GPP2 */
+	s_ppp = nm_connection_get_setting_ppp (connection);
+	if (!s_ppp) {
+		s_ppp = (NMSettingPPP *) nm_setting_ppp_new ();
+		g_object_set (G_OBJECT (s_ppp),
+		              NM_SETTING_PPP_LCP_ECHO_FAILURE, 5,
+		              NM_SETTING_PPP_LCP_ECHO_INTERVAL, 30,
+		              NULL);
+		nm_connection_add_setting (connection, NM_SETTING (s_ppp));
+	}
+
+	if (MODEM_CAPS_3GPP (modem_caps)) {
+		NMSettingGsm *s_gsm;
+
+		s_gsm = nm_connection_get_setting_gsm (connection);
+		if (!s_gsm || !nm_setting_gsm_get_apn (s_gsm)) {
+			/* Need an APN at least */
+			g_set_error_literal (error,
+			                     NM_SETTING_GSM_ERROR,
+			                     NM_SETTING_GSM_ERROR_MISSING_PROPERTY,
+			                     NM_SETTING_GSM_APN);
+			return FALSE;
+		}
+
+		/* TODO: This is not needed */
+		if (!nm_setting_gsm_get_number (s_gsm))
+			g_object_set (G_OBJECT (s_gsm), NM_SETTING_GSM_NUMBER, "*99#", NULL);
+
+		nm_utils_complete_generic (connection,
+		                           NM_SETTING_GSM_SETTING_NAME,
+		                           existing_connections,
+		                           _("GSM connection %d"),
+		                           NULL,
+		                           FALSE); /* No IPv6 yet by default */
+
+		return TRUE;
+	}
+
+	if (MODEM_CAPS_3GPP2 (modem_caps)) {
+		NMSettingCdma *s_cdma;
+
+		s_cdma = nm_connection_get_setting_cdma (connection);
+		if (!s_cdma) {
+			s_cdma = (NMSettingCdma *) nm_setting_cdma_new ();
+			nm_connection_add_setting (connection, NM_SETTING (s_cdma));
+		}
+
+		if (!nm_setting_cdma_get_number (s_cdma))
+			g_object_set (G_OBJECT (s_cdma), NM_SETTING_CDMA_NUMBER, "#777", NULL);
+
+		nm_utils_complete_generic (connection,
+		                           NM_SETTING_CDMA_SETTING_NAME,
+		                           existing_connections,
+		                           _("CDMA connection %d"),
+		                           NULL,
+		                           FALSE); /* No IPv6 yet by default */
+
+		return TRUE;
+	}
+
+	g_set_error (error,
+	             NM_MODEM_BROADBAND_ERROR,
+	             NM_MODEM_BROADBAND_ERROR_CONNECTION_INCOMPATIBLE,
+	             "Device is not a mobile broadband modem");
+	return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+get_user_pass (NMModem *modem,
+               NMConnection *connection,
+               const char **user,
+               const char **pass)
+{
+	NMSettingGsm *s_gsm;
+	NMSettingCdma *s_cdma;
+
+	s_gsm = nm_connection_get_setting_gsm (connection);
+	s_cdma = nm_connection_get_setting_cdma (connection);
+	if (!s_gsm && !s_cdma)
+		return FALSE;
+
+	if (user) {
+		if (s_gsm)
+			*user = nm_setting_gsm_get_username (s_gsm);
+		else if (s_cdma)
+			*user = nm_setting_cdma_get_username (s_cdma);
+	}
+	if (pass) {
+		if (s_gsm)
+			*pass = nm_setting_gsm_get_password (s_gsm);
+		else if (s_cdma)
+			*pass = nm_setting_cdma_get_password (s_cdma);
+	}
+
+	return TRUE;
+}
+
+/*****************************************************************************/
+
+static const char *
+get_setting_name (NMModem *_self)
+{
+	NMModemBroadband *self = NM_MODEM_BROADBAND (_self);
+	MMModemCapability modem_caps;
+
+	modem_caps = mm_modem_get_current_capabilities (self->priv->modem_iface);
+	if (MODEM_CAPS_3GPP (modem_caps))
+		return NM_SETTING_GSM_SETTING_NAME;
+
+	if (MODEM_CAPS_3GPP2 (modem_caps))
+		return NM_SETTING_CDMA_SETTING_NAME;
+
+	return "unknown";
+}
+
+/*****************************************************************************/
+/* Query/Update enabled state */
+
+static void
+update_mm_enabled (NMModem *self,
+                   gboolean new_enabled)
+{
+	if (nm_modem_get_mm_enabled (self) != new_enabled) {
+		g_object_set (self,
+		              NM_MODEM_ENABLED, new_enabled,
+		              NULL);
+	}
+}
+
+static void
+modem_disable_ready (MMModem *modem_iface,
+                     GAsyncResult *res,
+                     NMModemBroadband *self)
+{
+	GError *error = NULL;
+
+	if (!mm_modem_disable_finish (modem_iface, res, &error)) {
+		nm_log_warn (LOGD_MB, "(%s) failed to disable modem: %s",
+		             nm_modem_get_uid (NM_MODEM (self)),
+		             error && error->message ? error->message : "(unknown)");
+		g_clear_error (&error);
+	} else
+		/* Update enabled/disabled state again */
+		update_mm_enabled (NM_MODEM (self), FALSE);
+
+	/* Balance refcount */
+	g_object_unref (self);
+}
+
+static void
+modem_enable_ready (MMModem *modem_iface,
+                    GAsyncResult *res,
+                    NMModemBroadband *self)
+{
+	GError *error = NULL;
+
+	if (!mm_modem_enable_finish (modem_iface, res, &error)) {
+		nm_log_warn (LOGD_MB, "(%s) failed to enable modem: %s",
+		             nm_modem_get_uid (NM_MODEM (self)),
+		             error && error->message ? error->message : "(unknown)");
+		g_clear_error (&error);
+	} else
+		update_mm_enabled (NM_MODEM (self), TRUE);
+
+	/* Balance refcount */
+	g_object_unref (self);
+}
+
+static void
+set_mm_enabled (NMModem *_self,
+                gboolean enabled)
+{
+	NMModemBroadband *self = NM_MODEM_BROADBAND (_self);
+
+	if (enabled) {
+		/* Don't even try to enable if we're known to be already locked */
+		if (mm_modem_get_state (self->priv->modem_iface) == MM_MODEM_STATE_LOCKED) {
+			nm_log_warn (LOGD_MB, "(%s) cannot enable modem: locked",
+			             nm_modem_get_uid (NM_MODEM (self)));
+			g_signal_emit_by_name (self, NM_MODEM_AUTH_REQUESTED, 0);
+			return;
+		}
+
+		mm_modem_enable (self->priv->modem_iface,
+		                 NULL, /* cancellable */
+		                 (GAsyncReadyCallback)modem_enable_ready,
+		                 g_object_ref (self));
+	} else {
+		mm_modem_disable (self->priv->modem_iface,
+		                  NULL, /* cancellable */
+		                  (GAsyncReadyCallback)modem_disable_ready,
+		                  g_object_ref (self));
+
+		/* When disabling don't say we're enabled */
+		update_mm_enabled (NM_MODEM (self), enabled);
+	}
+}
+
+/*****************************************************************************/
+/* IP method static */
+
+static gboolean
+ip_string_to_network_address (const gchar *str,
+                              guint32 *out)
+{
+	struct in_addr addr;
+
+	/* IP address */
+	if (inet_pton (AF_INET, str, &addr) <= 0)
+		return FALSE;
+
+	*out = (guint32)addr.s_addr;
+	return TRUE;
+}
+
+static gboolean
+static_stage3_done (NMModemBroadband *self)
+{
+	GError *error = NULL;
+	NMIP4Config *config = NULL;
+	const gchar *address_string;
+	guint32 address_network;
+	NMIP4Address *addr;
+	const gchar **dns;
+	guint i;
+	guint prefix;
+
+	g_assert (self->priv->ipv4_config);
+
+	nm_log_info (LOGD_MB, "(%s): IPv4 static configuration:",
+	             nm_modem_get_uid (NM_MODEM (self)));
+
+	/* Fully fail if invalid IP address retrieved */
+	address_string = mm_bearer_ip_config_get_address (self->priv->ipv4_config);
+	if (!ip_string_to_network_address (address_string, &address_network)) {
+		error = g_error_new (NM_MODEM_BROADBAND_ERROR,
+		                     NM_MODEM_BROADBAND_ERROR_CONNECTION_INVALID,
+		                     "(%s) retrieving IP4 configuration failed: invalid address given '%s'",
+		                     nm_modem_get_uid (NM_MODEM (self)),
+		                     address_string);
+		goto out;
+	}
+
+	config = nm_ip4_config_new ();
+	addr = nm_ip4_address_new ();
+	nm_ip4_address_set_address (addr, address_network);
+	prefix = mm_bearer_ip_config_get_prefix (self->priv->ipv4_config);
+	if (prefix > 0)
+		nm_ip4_address_set_prefix (addr, prefix);
+	nm_ip4_config_take_address (config, addr);
+
+	nm_log_info (LOGD_MB, "  address %s/%d",
+	             mm_bearer_ip_config_get_address (self->priv->ipv4_config),
+	             mm_bearer_ip_config_get_prefix (self->priv->ipv4_config));
+
+	/* DNS servers */
+	dns = mm_bearer_ip_config_get_dns (self->priv->ipv4_config);
+	for (i = 0; dns[i]; i++) {
+		if (   ip_string_to_network_address (dns[i], &address_network)
+		    && address_network > 0) {
+			nm_ip4_config_add_nameserver (config, address_network);
+			nm_log_info (LOGD_MB, "  DNS %s", dns[i]);
+		}
+	}
+
+out:
+	g_signal_emit_by_name (self, NM_MODEM_IP4_CONFIG_RESULT, config, error);
+	g_clear_error (&error);
+	return FALSE;
+}
+
+static NMActStageReturn
+static_stage3_ip4_config_start (NMModem *_self,
+                                NMActRequest *req,
+                                NMDeviceStateReason *reason)
+{
+	NMModemBroadband *self = NM_MODEM_BROADBAND (_self);
+
+	/* We schedule it in an idle just to follow the same logic as in the
+	 * generic modem implementation. */
+	g_idle_add ((GSourceFunc)static_stage3_done, self);
+
+	return NM_ACT_STAGE_RETURN_POSTPONE;
+}
+
+/*****************************************************************************/
+/* Disconnect */
+
+typedef struct {
+	NMModemBroadband *self;
+	gboolean warn;
+} SimpleDisconnectContext;
+
+static void
+simple_disconnect_context_free (SimpleDisconnectContext *ctx)
+{
+	g_object_unref (ctx->self);
+	g_slice_free (SimpleDisconnectContext, ctx);
+}
+
+static void
+simple_disconnect_ready (MMModemSimple *modem_iface,
+                         GAsyncResult *res,
+                         SimpleDisconnectContext *ctx)
+{
+	GError *error = NULL;
+
+	if (!mm_modem_simple_disconnect_finish (modem_iface, res, &error)) {
+		if (ctx->warn)
+			nm_log_warn (LOGD_MB, "(%s) failed to disconnect modem: %s",
+			             nm_modem_get_uid (NM_MODEM (ctx->self)),
+			             error && error->message ? error->message : "(unknown)");
+		g_clear_error (&error);
+	}
+
+	simple_disconnect_context_free (ctx);
+}
+
+static void
+disconnect (NMModem *self,
+            gboolean warn)
+{
+	SimpleDisconnectContext *ctx;
+
+	ctx = g_slice_new (SimpleDisconnectContext);
+	ctx->self = g_object_ref (self);
+
+	/* Don't bother warning on FAILED since the modem is already gone */
+	ctx->warn = warn;
+
+	mm_modem_simple_disconnect (
+		ctx->self->priv->simple_iface,
+		NULL, /* bearer path; if NULL given ALL get disconnected */
+		NULL, /* cancellable */
+		(GAsyncReadyCallback)simple_disconnect_ready,
+		ctx);
+}
+
+/*****************************************************************************/
+
+static void
+deactivate (NMModem *_self, NMDevice *device)
+{
+	NMModemBroadband *self = NM_MODEM_BROADBAND (_self);
+
+	/* TODO: cancel SimpleConnect() if any */
+
+	/* Cleanup IPv4 addresses and routes */
+	g_clear_object (&self->priv->ipv4_config);
+	g_clear_object (&self->priv->ipv6_config);
+	g_clear_object (&self->priv->bearer);
+
+	self->priv->pin_tries = 0;
+
+	/* Chain up parent's */
+	NM_MODEM_CLASS (nm_modem_broadband_parent_class)->deactivate (_self, device);
+}
+
+/*****************************************************************************/
+
+static void
+modem_state_changed (MMModem *modem,
+                     MMModemState old_state,
+                     MMModemState new_state,
+                     MMModemStateChangeReason reason,
+                     NMModemBroadband *self)
+{
+	gboolean old;
+	gboolean new;
+
+	nm_log_info (LOGD_MB, "(%s) state changed, '%s' --> '%s' (reason: %s)\n",
+	             nm_modem_get_uid (NM_MODEM (self)),
+	             mm_modem_state_get_string (old_state),
+	             mm_modem_state_get_string (new_state),
+	             mm_modem_state_change_reason_get_string (reason));
+
+	old = nm_modem_get_mm_enabled (NM_MODEM (self));
+	new = (mm_modem_get_state (self->priv->modem_iface) >= MM_MODEM_STATE_ENABLED);
+	if (old != new)
+		g_object_set (self,
+		              NM_MODEM_ENABLED, new,
+		              NULL);
+
+	old = nm_modem_get_mm_connected (NM_MODEM (self));
+	new = (mm_modem_get_state (self->priv->modem_iface) >= MM_MODEM_STATE_CONNECTED);
+	if (old != new)
+		g_object_set (self,
+		              NM_MODEM_CONNECTED, new,
+		              NULL);
+}
+
+/*****************************************************************************/
+
+NMModem *
+nm_modem_broadband_new (GObject *object)
+{
+	MMObject *modem_object;
+	MMModem *modem_iface;
+
+	g_return_val_if_fail (MM_IS_OBJECT (object), NULL);
+	modem_object = MM_OBJECT (object);
+
+	/* Ensure we have the 'Modem' interface and the primary port at least */
+	modem_iface = mm_object_peek_modem (modem_object);
+	g_return_val_if_fail (!!modem_iface, NULL);
+	g_return_val_if_fail (!!mm_modem_get_primary_port (modem_iface), NULL);
+
+	/* If the modem is in 'FAILED' state we cannot do anything with it.
+	 * This happens when a severe error happened when trying to initialize it,
+	 * like missing SIM. */
+	if (mm_modem_get_state (modem_iface) == MM_MODEM_STATE_FAILED) {
+		nm_log_warn (LOGD_MB, "(%s): unusable modem detected",
+					 mm_modem_get_primary_port (modem_iface));
+		return NULL;
+	}
+
+	return (NMModem *) g_object_new (NM_TYPE_MODEM_BROADBAND,
+	                                 NM_MODEM_PATH, mm_object_get_path (modem_object),
+	                                 NM_MODEM_UID, mm_modem_get_primary_port (modem_iface),
+	                                 NM_MODEM_CONTROL_PORT, mm_modem_get_primary_port (modem_iface),
+	                                 NM_MODEM_DATA_PORT, NULL, /* We don't know it until bearer created */
+	                                 NM_MODEM_BROADBAND_MODEM, modem_object,
+	                                 NULL);
+}
+
+static void
+nm_modem_broadband_init (NMModemBroadband *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+	                                          NM_TYPE_MODEM_BROADBAND,
+	                                          NMModemBroadbandPrivate);
+}
+
+static void
+set_property (GObject *object,
+              guint prop_id,
+			  const GValue *value,
+              GParamSpec *pspec)
+{
+	NMModemBroadband *self = NM_MODEM_BROADBAND (object);
+
+	switch (prop_id) {
+	case PROP_MODEM:
+		/* construct-only */
+		self->priv->modem_object = g_value_dup_object (value);
+		self->priv->modem_iface = mm_object_get_modem (self->priv->modem_object);
+		g_assert (self->priv->modem_iface != NULL);
+		g_signal_connect (self->priv->modem_iface,
+                          "state-changed",
+                          G_CALLBACK (modem_state_changed),
+                          self);
+
+		g_object_set (object,
+		              NM_MODEM_ENABLED, (mm_modem_get_state (self->priv->modem_iface) >= MM_MODEM_STATE_ENABLED),
+		              NM_MODEM_CONNECTED, (mm_modem_get_state (self->priv->modem_iface) >= MM_MODEM_STATE_CONNECTED),
+		              NULL);
+
+		/* Note: don't grab the Simple iface here; the Modem interface is the
+		 * only one assumed to be always valid and available */
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+get_property (GObject *object,
+              guint prop_id,
+			  GValue *value,
+              GParamSpec *pspec)
+{
+	NMModemBroadband *self = NM_MODEM_BROADBAND (object);
+
+	switch (prop_id) {
+	case PROP_MODEM:
+		g_value_set_object (value, self->priv->modem_object);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+dispose (GObject *object)
+{
+	NMModemBroadband *self = NM_MODEM_BROADBAND (object);
+
+	g_clear_object (&self->priv->ipv4_config);
+	g_clear_object (&self->priv->ipv6_config);
+	g_clear_object (&self->priv->bearer);
+	g_clear_object (&self->priv->modem_iface);
+	g_clear_object (&self->priv->simple_iface);
+	g_clear_object (&self->priv->modem_object);
+
+	G_OBJECT_CLASS (nm_modem_broadband_parent_class)->dispose (object);
+}
+
+static void
+nm_modem_broadband_class_init (NMModemBroadbandClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	NMModemClass *modem_class = NM_MODEM_CLASS (klass);
+
+	g_type_class_add_private (object_class, sizeof (NMModemBroadbandPrivate));
+
+	/* Virtual methods */
+	object_class->dispose = dispose;
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
+
+	modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start;
+	modem_class->disconnect = disconnect;
+	modem_class->deactivate = deactivate;
+	modem_class->set_mm_enabled = set_mm_enabled;
+	modem_class->get_user_pass = get_user_pass;
+	modem_class->get_setting_name = get_setting_name;
+	modem_class->get_best_auto_connection = get_best_auto_connection;
+	modem_class->check_connection_compatible = check_connection_compatible;
+	modem_class->complete_connection = complete_connection;
+	modem_class->act_stage1_prepare = act_stage1_prepare;
+
+	/* Properties */
+	g_object_class_install_property
+		(object_class, PROP_MODEM,
+		 g_param_spec_object (NM_MODEM_BROADBAND_MODEM,
+		                      "Modem",
+		                      "Broadband modem object",
+		                      MM_GDBUS_TYPE_OBJECT,
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
diff --git a/src/modem-manager/nm-modem-broadband.h b/src/modem-manager/nm-modem-broadband.h
new file mode 100644
index 00000000..005c3853
--- /dev/null
+++ b/src/modem-manager/nm-modem-broadband.h
@@ -0,0 +1,69 @@
+/* -*- 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) 2012 - Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#ifndef NM_MODEM_BROADBAND_H
+#define NM_MODEM_BROADBAND_H
+
+#include <dbus/dbus-glib.h>
+#include <glib-object.h>
+#include "nm-modem.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_MODEM_BROADBAND            (nm_modem_broadband_get_type ())
+#define NM_MODEM_BROADBAND(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadband))
+#define NM_MODEM_BROADBAND_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_MODEM_BROADBAND, NMModemBroadbandClass))
+#define NM_IS_MODEM_BROADBAND(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_BROADBAND))
+#define NM_IS_MODEM_BROADBAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_MODEM_BROADBAND))
+#define NM_MODEM_BROADBAND_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_MODEM_BROADBAND, NMModemBroadbandClass))
+
+#define NM_MODEM_BROADBAND_MODEM "modem"
+
+typedef struct _NMModemBroadband        NMModemBroadband;
+typedef struct _NMModemBroadbandClass   NMModemBroadbandClass;
+typedef struct _NMModemBroadbandPrivate NMModemBroadbandPrivate;
+
+typedef enum {
+	NM_MODEM_BROADBAND_ERROR_CONNECTION_NOT_GSM,      /*< nick=ConnectionNotGsm >*/
+	NM_MODEM_BROADBAND_ERROR_CONNECTION_NOT_CDMA,     /*< nick=ConnectionNotCdma >*/
+	NM_MODEM_BROADBAND_ERROR_CONNECTION_INVALID,      /*< nick=ConnectionInvalid >*/
+	NM_MODEM_BROADBAND_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/
+} NMModemBroadbandError;
+
+struct _NMModemBroadband {
+	NMModem parent;
+	NMModemBroadbandPrivate *priv;
+};
+
+struct _NMModemBroadbandClass {
+	NMModemClass parent;
+};
+
+GType nm_modem_broadband_get_type (void);
+
+NMModem *nm_modem_broadband_new (GObject *object);
+
+void nm_modem_broadband_get_capabilities (NMModemBroadband *self,
+                                          NMDeviceModemCapabilities *modem_caps,
+                                          NMDeviceModemCapabilities *current_caps);
+
+G_END_DECLS
+
+#endif /* NM_MODEM_BROADBAND_H */
diff --git a/src/modem-manager/nm-modem-cdma.c b/src/modem-manager/nm-modem-cdma.c
index fa19a342..73c87c28 100644
--- a/src/modem-manager/nm-modem-cdma.c
+++ b/src/modem-manager/nm-modem-cdma.c
@@ -37,7 +37,7 @@
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
 
-G_DEFINE_TYPE (NMModemCdma, nm_modem_cdma, NM_TYPE_MODEM)
+G_DEFINE_TYPE (NMModemCdma, nm_modem_cdma, NM_TYPE_MODEM_GENERIC)
 
 #define NM_MODEM_CDMA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM_CDMA, NMModemCdmaPrivate))
 
@@ -62,19 +62,20 @@ nm_cdma_error_quark (void)
 
 NMModem *
 nm_modem_cdma_new (const char *path,
-                   const char *device,
                    const char *data_device,
-                   guint32 ip_method)
+                   guint32 ip_method,
+                   NMModemState state)
 {
 	g_return_val_if_fail (path != NULL, NULL);
-	g_return_val_if_fail (device != NULL, NULL);
 	g_return_val_if_fail (data_device != NULL, NULL);
 
 	return (NMModem *) g_object_new (NM_TYPE_MODEM_CDMA,
 	                                 NM_MODEM_PATH, path,
-	                                 NM_MODEM_DEVICE, device,
-	                                 NM_MODEM_IFACE, data_device,
+	                                 NM_MODEM_UID, data_device,
+	                                 NM_MODEM_CONTROL_PORT, NULL,
+	                                 NM_MODEM_DATA_PORT, data_device,
 	                                 NM_MODEM_IP_METHOD, ip_method,
+	                                 NM_MODEM_CONNECTED, (state == NM_MODEM_STATE_CONNECTED),
 	                                 NULL);
 }
 
@@ -109,7 +110,7 @@ do_connect (NMModemCdma *self)
 	NMModemCdmaPrivate *priv = NM_MODEM_CDMA_GET_PRIVATE (self);
 	DBusGProxy *proxy;
 
-	proxy = nm_modem_get_proxy (NM_MODEM (self), MM_DBUS_INTERFACE_MODEM_SIMPLE);
+	proxy = nm_modem_generic_get_proxy (NM_MODEM_GENERIC (self), MM_OLD_DBUS_INTERFACE_MODEM_SIMPLE);
 	priv->call = dbus_g_proxy_begin_call_with_timeout (proxy,
 	                                                   "Connect", stage1_prepare_done,
 	                                                   self, NULL, 120000,
@@ -152,11 +153,11 @@ create_connect_properties (NMConnection *connection)
 }
 
 static NMActStageReturn
-real_act_stage1_prepare (NMModem *modem,
-                         NMActRequest *req,
-                         GPtrArray **out_hints,
-                         const char **out_setting_name,
-                         NMDeviceStateReason *reason)
+act_stage1_prepare (NMModem *modem,
+                    NMActRequest *req,
+                    GPtrArray **out_hints,
+                    const char **out_setting_name,
+                    NMDeviceStateReason *reason)
 {
 	NMModemCdma *self = NM_MODEM_CDMA (modem);
 	NMModemCdmaPrivate *priv = NM_MODEM_CDMA_GET_PRIVATE (self);
@@ -177,7 +178,7 @@ real_act_stage1_prepare (NMModem *modem,
 		if (enabled)
 			do_connect (self);
 		else {
-			proxy = nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM);
+			proxy = nm_modem_generic_get_proxy (NM_MODEM_GENERIC (modem), MM_OLD_DBUS_INTERFACE_MODEM);
 			dbus_g_proxy_begin_call_with_timeout (proxy,
 			                                      "Enable", stage1_enable_done,
 			                                      modem, NULL, 20000,
@@ -192,9 +193,9 @@ real_act_stage1_prepare (NMModem *modem,
 }
 
 static NMConnection *
-real_get_best_auto_connection (NMModem *modem,
-							   GSList *connections,
-							   char **specific_object)
+get_best_auto_connection (NMModem *modem,
+                          GSList *connections,
+                          char **specific_object)
 {
 	GSList *iter;
 
@@ -217,9 +218,9 @@ real_get_best_auto_connection (NMModem *modem,
 }
 
 static gboolean
-real_check_connection_compatible (NMModem *modem,
-                                  NMConnection *connection,
-                                  GError **error)
+check_connection_compatible (NMModem *modem,
+                             NMConnection *connection,
+                             GError **error)
 {
 	NMSettingConnection *s_con;
 	NMSettingCdma *s_cdma;
@@ -246,10 +247,10 @@ real_check_connection_compatible (NMModem *modem,
 }
 
 static gboolean
-real_complete_connection (NMModem *modem,
-                          NMConnection *connection,
-                          const GSList *existing_connections,
-                          GError **error)
+complete_connection (NMModem *modem,
+                     NMConnection *connection,
+                     const GSList *existing_connections,
+                     GError **error)
 {
 	NMSettingCdma *s_cdma;
 	NMSettingPPP *s_ppp;
@@ -284,10 +285,10 @@ real_complete_connection (NMModem *modem,
 }
 
 static gboolean
-real_get_user_pass (NMModem *modem,
-                    NMConnection *connection,
-                    const char **user,
-                    const char **pass)
+get_user_pass (NMModem *modem,
+               NMConnection *connection,
+               const char **user,
+               const char **pass)
 {
 	NMSettingCdma *s_cdma;
 
@@ -304,25 +305,25 @@ real_get_user_pass (NMModem *modem,
 }
 
 static const char *
-real_get_setting_name (NMModem *modem)
+get_setting_name (NMModem *modem)
 {
 	return NM_SETTING_CDMA_SETTING_NAME;
 }
 
 static void
-real_deactivate (NMModem *modem, NMDevice *device)
+deactivate (NMModem *modem, NMDevice *device)
 {
 	NMModemCdmaPrivate *priv = NM_MODEM_CDMA_GET_PRIVATE (modem);
 
 	if (priv->call) {
 		DBusGProxy *proxy;
 
-		proxy = nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM_SIMPLE);
+		proxy = nm_modem_generic_get_proxy (NM_MODEM_GENERIC (modem), MM_OLD_DBUS_INTERFACE_MODEM_SIMPLE);
 		dbus_g_proxy_cancel_call (proxy, priv->call);
 		priv->call = NULL;
 	}
 
-	NM_MODEM_CLASS (nm_modem_cdma_parent_class)->deactivate (modem, device);	
+	NM_MODEM_CLASS (nm_modem_cdma_parent_class)->deactivate (modem, device);
 }
 
 /*****************************************************************************/
@@ -354,13 +355,13 @@ nm_modem_cdma_class_init (NMModemCdmaClass *klass)
 
 	/* Virtual methods */
 	object_class->dispose = dispose;
-	modem_class->get_user_pass = real_get_user_pass;
-	modem_class->get_setting_name = real_get_setting_name;
-	modem_class->get_best_auto_connection = real_get_best_auto_connection;
-	modem_class->check_connection_compatible = real_check_connection_compatible;
-	modem_class->complete_connection = real_complete_connection;
-	modem_class->act_stage1_prepare = real_act_stage1_prepare;
-	modem_class->deactivate = real_deactivate;
+	modem_class->get_user_pass = get_user_pass;
+	modem_class->get_setting_name = get_setting_name;
+	modem_class->get_best_auto_connection = get_best_auto_connection;
+	modem_class->check_connection_compatible = check_connection_compatible;
+	modem_class->complete_connection = complete_connection;
+	modem_class->act_stage1_prepare = act_stage1_prepare;
+	modem_class->deactivate = deactivate;
 
 	dbus_g_error_domain_register (NM_CDMA_ERROR, NULL, NM_TYPE_CDMA_ERROR);
 }
diff --git a/src/modem-manager/nm-modem-cdma.h b/src/modem-manager/nm-modem-cdma.h
index 2229c183..ab1b4874 100644
--- a/src/modem-manager/nm-modem-cdma.h
+++ b/src/modem-manager/nm-modem-cdma.h
@@ -22,14 +22,14 @@
 #ifndef NM_MODEM_CDMA_H
 #define NM_MODEM_CDMA_H
 
-#include <nm-modem.h>
+#include <nm-modem-generic.h>
 
 G_BEGIN_DECLS
 
-#define NM_TYPE_MODEM_CDMA			  (nm_modem_cdma_get_type ())
-#define NM_MODEM_CDMA(obj)			  (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_CDMA, NMModemCdma))
-#define NM_MODEM_CDMA_CLASS(klass)	  (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_MODEM_CDMA, NMModemCdmaClass))
-#define NM_IS_MODEM_CDMA(obj)		  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_CDMA))
+#define NM_TYPE_MODEM_CDMA            (nm_modem_cdma_get_type ())
+#define NM_MODEM_CDMA(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_CDMA, NMModemCdma))
+#define NM_MODEM_CDMA_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_MODEM_CDMA, NMModemCdmaClass))
+#define NM_IS_MODEM_CDMA(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_CDMA))
 #define NM_IS_MODEM_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_MODEM_CDMA))
 #define NM_MODEM_CDMA_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_MODEM_CDMA, NMModemCdmaClass))
 
@@ -40,22 +40,19 @@ typedef enum {
 } NMCdmaError;
 
 typedef struct {
-	NMModem parent;
+	NMModemGeneric parent;
 } NMModemCdma;
 
 typedef struct {
-	NMModemClass parent;
-
-	/* Signals */
-	void (*signal_quality) (NMModemCdma *self, guint32 quality);
+	NMModemGenericClass parent;
 } NMModemCdmaClass;
 
 GType nm_modem_cdma_get_type (void);
 
 NMModem *nm_modem_cdma_new (const char *path,
-                            const char *device,
                             const char *data_device,
-                            guint32 ip_method);
+                            guint32 ip_method,
+                            NMModemState state);
 
 G_END_DECLS
 
diff --git a/src/modem-manager/nm-modem-generic.c b/src/modem-manager/nm-modem-generic.c
new file mode 100644
index 00000000..f4e7a52f
--- /dev/null
+++ b/src/modem-manager/nm-modem-generic.c
@@ -0,0 +1,445 @@
+/* -*- 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) 2009 - 2011 Red Hat, Inc.
+ * Copyright (C) 2009 Novell, Inc.
+ */
+
+#include <string.h>
+#include "nm-modem-generic.h"
+#include "nm-system.h"
+#include "nm-dbus-manager.h"
+#include "nm-setting-connection.h"
+#include "nm-marshal.h"
+#include "nm-properties-changed-signal.h"
+#include "nm-modem-types.h"
+#include "nm-logging.h"
+#include "NetworkManagerUtils.h"
+#include "nm-device-private.h"
+#include "nm-dbus-glib-types.h"
+
+G_DEFINE_TYPE (NMModemGeneric, nm_modem_generic, NM_TYPE_MODEM)
+
+#define NM_MODEM_GENERIC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM_GENERIC, NMModemGenericPrivate))
+
+typedef struct {
+	NMDBusManager *dbus_mgr;
+	DBusGProxy *proxy;
+	DBusGProxy *props_proxy;
+
+	DBusGProxyCall *call;
+
+	NMModemState state;
+} NMModemGenericPrivate;
+
+/*****************************************************************************/
+
+DBusGProxy *
+nm_modem_generic_get_proxy (NMModemGeneric *self,
+                            const char *interface)
+{
+
+	NMModemGenericPrivate *priv = NM_MODEM_GENERIC_GET_PRIVATE (self);
+	const char *current_iface;
+
+	g_return_val_if_fail (NM_IS_MODEM_GENERIC (self), NULL);
+
+	/* Default to the default interface. */
+	if (interface == NULL)
+		interface = MM_OLD_DBUS_INTERFACE_MODEM;
+
+	if (interface && !strcmp (interface, DBUS_INTERFACE_PROPERTIES))
+		return priv->props_proxy;
+
+	current_iface = dbus_g_proxy_get_interface (priv->proxy);
+	if (!current_iface || strcmp (current_iface, interface))
+		dbus_g_proxy_set_interface (priv->proxy, interface);
+
+	return priv->proxy;
+}
+
+/*****************************************************************************/
+/* Query/Update enabled state */
+
+static void
+update_mm_enabled (NMModem *self,
+                   gboolean new_enabled)
+{
+	if (nm_modem_get_mm_enabled (self) != new_enabled) {
+		g_object_set (self,
+		              NM_MODEM_ENABLED, new_enabled,
+		              NULL);
+	}
+}
+
+static void
+get_mm_enabled_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+{
+	NMModem *self = NM_MODEM (user_data);
+	GError *error = NULL;
+	GValue value = { 0, };
+
+	if (!dbus_g_proxy_end_call (proxy, call_id, &error,
+	                            G_TYPE_VALUE, &value,
+	                            G_TYPE_INVALID)) {
+		nm_log_warn (LOGD_MB, "failed get modem enabled state: (%d) %s",
+		             error ? error->code : -1,
+		             error && error->message ? error->message : "(unknown)");
+		return;
+	}
+
+	if (G_VALUE_HOLDS_BOOLEAN (&value)) {
+		update_mm_enabled (self, g_value_get_boolean (&value));
+	} else
+		nm_log_warn (LOGD_MB, "failed get modem enabled state: unexpected reply type");
+
+	g_value_unset (&value);
+}
+
+static void
+query_mm_enabled (NMModemGeneric *self)
+{
+	dbus_g_proxy_begin_call (NM_MODEM_GENERIC_GET_PRIVATE (self)->props_proxy,
+	                         "Get", get_mm_enabled_done,
+	                         self, NULL,
+	                         G_TYPE_STRING, MM_OLD_DBUS_INTERFACE_MODEM,
+	                         G_TYPE_STRING, "Enabled",
+	                         G_TYPE_INVALID);
+}
+
+static void
+set_mm_enabled_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+{
+	GError *error = NULL;
+
+	if (!dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) {
+		nm_log_warn (LOGD_MB, "failed to enable/disable modem: (%d) %s",
+		             error ? error->code : -1,
+		             error && error->message ? error->message : "(unknown)");
+	}
+
+	/* Update enabled/disabled state again */
+	query_mm_enabled (NM_MODEM_GENERIC (user_data));
+}
+
+static void
+set_mm_enabled (NMModem *self, gboolean enabled)
+{
+	/* FIXME: For now this just toggles the ModemManager enabled state.  In the
+	 * future we want to tie this into rfkill state instead so that the user can
+	 * toggle rfkill status of the WWAN modem.
+	 */
+	dbus_g_proxy_begin_call (nm_modem_generic_get_proxy (NM_MODEM_GENERIC (self),
+	                                                     MM_OLD_DBUS_INTERFACE_MODEM),
+	                         "Enable", set_mm_enabled_done,
+	                         self, NULL,
+	                         G_TYPE_BOOLEAN, enabled,
+	                         G_TYPE_INVALID);
+	/* If we are disabling the modem, stop saying that it's enabled. */
+	if (!enabled)
+		update_mm_enabled (self, enabled);
+}
+
+/*****************************************************************************/
+/* IP method static */
+
+static char addr_to_string_buf[INET6_ADDRSTRLEN + 1];
+
+static const char *
+ip_address_to_string (guint32 numeric)
+{
+	struct in_addr temp_addr;
+
+	memset (&addr_to_string_buf, '\0', sizeof (addr_to_string_buf));
+	temp_addr.s_addr = numeric;
+
+	if (inet_ntop (AF_INET, &temp_addr, addr_to_string_buf, INET_ADDRSTRLEN)) {
+		return addr_to_string_buf;
+	} else {
+		nm_log_warn (LOGD_VPN, "error converting IP4 address 0x%X",
+		             ntohl (temp_addr.s_addr));
+		return NULL;
+	}
+}
+
+static void
+static_stage3_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
+{
+	NMModemGeneric *self = NM_MODEM_GENERIC (user_data);
+	NMModemGenericPrivate *priv = NM_MODEM_GENERIC_GET_PRIVATE (self);
+	GValueArray *ret_array = NULL;
+	GError *error = NULL;
+	NMIP4Config *config = NULL;
+
+	priv->call = NULL;
+
+	/* Returned value array is (uuuu): [IP, DNS1, DNS2, DNS3], all in
+	 * network byte order.
+	 */
+	if (dbus_g_proxy_end_call (proxy, call, &error,
+	                           G_TYPE_VALUE_ARRAY, &ret_array,
+	                           G_TYPE_INVALID)) {
+		NMIP4Address *addr;
+		int i;
+
+		config = nm_ip4_config_new ();
+
+		addr = nm_ip4_address_new ();
+
+		nm_log_info (LOGD_MB, "(%s): IPv4 static configuration:",
+		             nm_modem_get_uid (NM_MODEM (self)));
+
+		/* IP address */
+		nm_ip4_address_set_address (addr, g_value_get_uint (g_value_array_get_nth (ret_array, 0)));
+		nm_ip4_address_set_prefix (addr, 32);
+		nm_ip4_config_take_address (config, addr);
+
+		nm_log_info (LOGD_MB, "  address %s/%d",
+		             ip_address_to_string (nm_ip4_address_get_address (addr)),
+		             nm_ip4_address_get_prefix (addr));
+
+		/* DNS servers */
+		for (i = 1; i < ret_array->n_values; i++) {
+			GValue *value = g_value_array_get_nth (ret_array, i);
+			guint32 tmp = g_value_get_uint (value);
+
+			if (tmp > 0) {
+				nm_ip4_config_add_nameserver (config, tmp);
+				nm_log_info (LOGD_MB, "  DNS %s", ip_address_to_string (tmp));
+			}
+		}
+		g_value_array_free (ret_array);
+	}
+
+	g_signal_emit_by_name (self, NM_MODEM_IP4_CONFIG_RESULT, config, error);
+	g_clear_error (&error);
+}
+
+static NMActStageReturn
+static_stage3_ip4_config_start (NMModem *self,
+                                NMActRequest *req,
+                                NMDeviceStateReason *reason)
+{
+	NMModemGenericPrivate *priv;
+
+	g_return_val_if_fail (self != NULL, NM_ACT_STAGE_RETURN_FAILURE);
+	g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE);
+	g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
+	g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE);
+	g_return_val_if_fail (reason !=	NULL, NM_ACT_STAGE_RETURN_FAILURE);
+
+	priv = NM_MODEM_GENERIC_GET_PRIVATE (self);
+
+	priv->call = dbus_g_proxy_begin_call (nm_modem_generic_get_proxy (NM_MODEM_GENERIC (self),
+	                                                                  MM_OLD_DBUS_INTERFACE_MODEM),
+	                                      "GetIP4Config", static_stage3_done,
+	                                      self, NULL,
+	                                      G_TYPE_INVALID);
+
+	return NM_ACT_STAGE_RETURN_POSTPONE;
+}
+
+/*****************************************************************************/
+
+static void
+disconnect_done (DBusGProxy *proxy,
+                 DBusGProxyCall *call_id,
+                 gpointer user_data)
+{
+	GError *error = NULL;
+	gboolean warn = GPOINTER_TO_UINT (user_data);
+
+	if (!dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID) && warn) {
+		nm_log_info (LOGD_MB, "disconnect failed: (%d) %s",
+		             error ? error->code : -1,
+		             error && error->message ? error->message : "(unknown)");
+	}
+}
+
+static void
+disconnect (NMModem *self,
+            gboolean warn)
+{
+	dbus_g_proxy_begin_call (nm_modem_generic_get_proxy (NM_MODEM_GENERIC (self),
+	                                                     MM_OLD_DBUS_INTERFACE_MODEM),
+	                         "Disconnect",
+	                         disconnect_done,
+	                         GUINT_TO_POINTER (warn),
+	                         NULL,
+	                         G_TYPE_INVALID);
+}
+
+/*****************************************************************************/
+
+static void
+deactivate (NMModem *self, NMDevice *device)
+{
+	NMModemGenericPrivate *priv;
+
+	g_assert (NM_IS_MODEM_GENERIC (self));
+	g_assert (NM_IS_DEVICE (device));
+
+	priv = NM_MODEM_GENERIC_GET_PRIVATE (self);
+
+	if (priv->call) {
+		dbus_g_proxy_cancel_call (priv->proxy, priv->call);
+		priv->call = NULL;
+	}
+
+	/* Chain up parent's */
+	NM_MODEM_CLASS (nm_modem_generic_parent_class)->deactivate (self, device);
+}
+
+/*****************************************************************************/
+
+static void
+modem_properties_changed (DBusGProxy *proxy,
+                          const char *interface,
+                          GHashTable *props,
+                          gpointer user_data)
+{
+	NMModemGeneric *self = NM_MODEM_GENERIC (user_data);
+	NMModemGenericPrivate *priv = NM_MODEM_GENERIC_GET_PRIVATE (self);
+	GValue *value;
+	NMModemState new_state;
+
+	if (strcmp (interface, MM_OLD_DBUS_INTERFACE_MODEM))
+		return;
+
+	value = g_hash_table_lookup (props, "Enabled");
+	if (value && G_VALUE_HOLDS_BOOLEAN (value)) {
+		g_object_set (self,
+		              NM_MODEM_ENABLED, g_value_get_boolean (value),
+		              NULL);
+	}
+
+	value = g_hash_table_lookup (props, "IpMethod");
+	if (value && G_VALUE_HOLDS_UINT (value)) {
+		g_object_set (self,
+		              NM_MODEM_IP_METHOD, g_value_get_uint (value),
+		              NULL);
+	}
+
+	value = g_hash_table_lookup (props, "State");
+	if (value && G_VALUE_HOLDS_UINT (value)) {
+		new_state = g_value_get_uint (value);
+		if (new_state != priv->state) {
+			if (new_state == NM_MODEM_STATE_CONNECTED)
+				g_object_set (self,
+				              NM_MODEM_CONNECTED, TRUE,
+				              NULL);
+			else if (priv->state == NM_MODEM_STATE_CONNECTED)
+				g_object_set (self,
+				              NM_MODEM_CONNECTED, FALSE,
+				              NULL);
+			priv->state = new_state;
+		}
+	}
+}
+
+/*****************************************************************************/
+
+static void
+nm_modem_generic_init (NMModemGeneric *self)
+{
+	NMModemGenericPrivate *priv = NM_MODEM_GENERIC_GET_PRIVATE (self);
+
+	priv->dbus_mgr = nm_dbus_manager_get ();
+}
+
+static GObject*
+constructor (GType type,
+			 guint n_construct_params,
+			 GObjectConstructParam *construct_params)
+{
+	GObject *object;
+	NMModemGenericPrivate *priv;
+	DBusGConnection *bus;
+
+	object = G_OBJECT_CLASS (nm_modem_generic_parent_class)->constructor (type, n_construct_params, construct_params);
+	if (!object)
+		return NULL;
+
+	priv = NM_MODEM_GENERIC_GET_PRIVATE (object);
+
+	bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
+	priv->proxy = dbus_g_proxy_new_for_name (bus,
+	                                         MM_OLD_DBUS_SERVICE,
+	                                         nm_modem_get_path (NM_MODEM (object)),
+	                                         MM_OLD_DBUS_INTERFACE_MODEM);
+
+	priv->props_proxy = dbus_g_proxy_new_for_name (bus,
+	                                               MM_OLD_DBUS_SERVICE,
+	                                               nm_modem_get_path (NM_MODEM (object)),
+	                                               DBUS_INTERFACE_PROPERTIES);
+	dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_BOXED,
+	                                   G_TYPE_NONE,
+	                                   G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT,
+	                                   G_TYPE_INVALID);
+	dbus_g_proxy_add_signal (priv->props_proxy, "MmPropertiesChanged",
+	                         G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT,
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->props_proxy, "MmPropertiesChanged",
+	                             G_CALLBACK (modem_properties_changed),
+	                             object,
+	                             NULL);
+
+	query_mm_enabled (NM_MODEM_GENERIC (object));
+
+	return object;
+}
+
+static void
+dispose (GObject *object)
+{
+	NMModemGenericPrivate *priv = NM_MODEM_GENERIC_GET_PRIVATE (object);
+
+	if (priv->proxy) {
+		g_object_unref (priv->proxy);
+		priv->proxy = NULL;
+	}
+
+	if (priv->props_proxy) {
+		g_object_unref (priv->props_proxy);
+		priv->props_proxy = NULL;
+	}
+
+	if (priv->dbus_mgr) {
+		g_object_unref (priv->dbus_mgr);
+		priv->dbus_mgr = NULL;
+	}
+
+	G_OBJECT_CLASS (nm_modem_generic_parent_class)->dispose (object);
+}
+
+static void
+nm_modem_generic_class_init (NMModemGenericClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	NMModemClass *modem_class = NM_MODEM_CLASS (klass);
+
+	g_type_class_add_private (object_class, sizeof (NMModemGenericPrivate));
+
+	/* Virtual methods */
+	object_class->constructor = constructor;
+	object_class->dispose = dispose;
+
+	modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start;
+	modem_class->disconnect = disconnect;
+	modem_class->deactivate = deactivate;
+	modem_class->set_mm_enabled = set_mm_enabled;
+}
diff --git a/src/modem-manager/nm-modem-generic.h b/src/modem-manager/nm-modem-generic.h
new file mode 100644
index 00000000..59866a1e
--- /dev/null
+++ b/src/modem-manager/nm-modem-generic.h
@@ -0,0 +1,69 @@
+/* -*- 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) 2009 - 2011 Red Hat, Inc.
+ * Copyright (C) 2009 Novell, Inc.
+ */
+
+#ifndef NM_MODEM_GENERIC_H
+#define NM_MODEM_GENERIC_H
+
+#include <dbus/dbus-glib.h>
+#include <glib-object.h>
+#include "nm-modem.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_MODEM_GENERIC            (nm_modem_generic_get_type ())
+#define NM_MODEM_GENERIC(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_GENERIC, NMModemGeneric))
+#define NM_MODEM_GENERIC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_MODEM_GENERIC, NMModemGenericClass))
+#define NM_IS_MODEM_GENERIC(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_GENERIC))
+#define NM_IS_MODEM_GENERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_MODEM_GENERIC))
+#define NM_MODEM_GENERIC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_MODEM_GENERIC, NMModemGenericClass))
+
+typedef enum {
+    NM_MODEM_STATE_UNKNOWN = 0,
+    NM_MODEM_STATE_DISABLED = 10,
+    NM_MODEM_STATE_DISABLING = 20,
+    NM_MODEM_STATE_ENABLING = 30,
+    NM_MODEM_STATE_ENABLED = 40,
+    NM_MODEM_STATE_SEARCHING = 50,
+    NM_MODEM_STATE_REGISTERED = 60,
+    NM_MODEM_STATE_DISCONNECTING = 70,
+    NM_MODEM_STATE_CONNECTING = 80,
+    NM_MODEM_STATE_CONNECTED = 90,
+
+    NM_MODEM_STATE_LAST = NM_MODEM_STATE_CONNECTED
+} NMModemState;
+
+typedef struct {
+	NMModem parent;
+} NMModemGeneric;
+
+typedef struct {
+	NMModemClass parent;
+} NMModemGenericClass;
+
+GType nm_modem_generic_get_type (void);
+
+/* Protected */
+DBusGProxy *nm_modem_generic_get_proxy (NMModemGeneric *modem,
+                                        const gchar *interface);
+
+G_END_DECLS
+
+#endif /* NM_MODEM_GENERIC_H */
diff --git a/src/modem-manager/nm-modem-gsm.c b/src/modem-manager/nm-modem-gsm.c
index 183b4780..b6d3c857 100644
--- a/src/modem-manager/nm-modem-gsm.c
+++ b/src/modem-manager/nm-modem-gsm.c
@@ -58,8 +58,10 @@ typedef enum {
     MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED = 2,
     MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY      = 3,
     MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY      = 4,
+    MM_MODEM_GSM_ALLOWED_MODE_4G_PREFERRED = 5,
+    MM_MODEM_GSM_ALLOWED_MODE_4G_ONLY      = 6,
 
-    MM_MODEM_GSM_ALLOWED_MODE_LAST = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY
+    MM_MODEM_GSM_ALLOWED_MODE_LAST = MM_MODEM_GSM_ALLOWED_MODE_4G_ONLY
 } MMModemGsmAllowedMode;
 
 typedef enum {
@@ -75,7 +77,7 @@ typedef enum {
     MM_MODEM_GSM_ALLOWED_AUTH_LAST = MM_MODEM_GSM_ALLOWED_AUTH_EAP
 } MMModemGsmAllowedAuth;
 
-G_DEFINE_TYPE (NMModemGsm, nm_modem_gsm, NM_TYPE_MODEM)
+G_DEFINE_TYPE (NMModemGsm, nm_modem_gsm, NM_TYPE_MODEM_GENERIC)
 
 #define NM_MODEM_GSM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM_GSM, NMModemGsmPrivate))
 
@@ -102,19 +104,20 @@ nm_gsm_error_quark (void)
 
 NMModem *
 nm_modem_gsm_new (const char *path,
-                  const char *device,
                   const char *data_device,
-                  guint32 ip_method)
+                  guint32 ip_method,
+                  NMModemState state)
 {
 	g_return_val_if_fail (path != NULL, NULL);
-	g_return_val_if_fail (device != NULL, NULL);
 	g_return_val_if_fail (data_device != NULL, NULL);
 
 	return (NMModem *) g_object_new (NM_TYPE_MODEM_GSM,
 	                                 NM_MODEM_PATH, path,
-	                                 NM_MODEM_DEVICE, device,
-	                                 NM_MODEM_IFACE, data_device,
+	                                 NM_MODEM_UID, data_device,
+	                                 NM_MODEM_CONTROL_PORT, NULL,
+	                                 NM_MODEM_DATA_PORT, data_device,
 	                                 NM_MODEM_IP_METHOD, ip_method,
+	                                 NM_MODEM_CONNECTED, (state == NM_MODEM_STATE_CONNECTED),
 	                                 NULL);
 }
 
@@ -222,12 +225,12 @@ do_connect (NMModemGsm *self)
 	NMModemGsmPrivate *priv = NM_MODEM_GSM_GET_PRIVATE (self);
 	DBusGProxy *proxy;
 
-	proxy = nm_modem_get_proxy (NM_MODEM (self), MM_DBUS_INTERFACE_MODEM_SIMPLE);
-	dbus_g_proxy_begin_call_with_timeout (proxy,
-	                                      "Connect", stage1_prepare_done,
-	                                      self, NULL, 120000,
-	                                      DBUS_TYPE_G_MAP_OF_VARIANT, priv->connect_properties,
-	                                      G_TYPE_INVALID);
+	proxy = nm_modem_generic_get_proxy (NM_MODEM_GENERIC (self), MM_OLD_DBUS_INTERFACE_MODEM_SIMPLE);
+	priv->call = dbus_g_proxy_begin_call_with_timeout (proxy,
+	                                                   "Connect", stage1_prepare_done,
+	                                                   self, NULL, 120000,
+	                                                   DBUS_TYPE_G_MAP_OF_VARIANT, priv->connect_properties,
+	                                                   G_TYPE_INVALID);
 }
 
 static void stage1_enable_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data);
@@ -242,7 +245,7 @@ do_enable (NMModemGsm *self)
 	g_return_val_if_fail (NM_IS_MODEM_GSM (self), FALSE);
 
 	NM_MODEM_GSM_GET_PRIVATE (self)->enable_delay_id = 0;
-	proxy = nm_modem_get_proxy (NM_MODEM (self), MM_DBUS_INTERFACE_MODEM);
+	proxy = nm_modem_generic_get_proxy (NM_MODEM_GENERIC (self), MM_OLD_DBUS_INTERFACE_MODEM);
 	dbus_g_proxy_begin_call_with_timeout (proxy,
 	                                      "Enable", stage1_enable_done,
 	                                      self, NULL, 20000,
@@ -295,7 +298,7 @@ handle_enable_pin_required (NMModemGsm *self)
 
 	/* If we do, send it */
 	if (pin) {
-		proxy = nm_modem_get_proxy (NM_MODEM (self), MM_DBUS_INTERFACE_MODEM_GSM_CARD);
+		proxy = nm_modem_generic_get_proxy (NM_MODEM_GENERIC (self), MM_OLD_DBUS_INTERFACE_MODEM_GSM_CARD);
 		dbus_g_proxy_begin_call_with_timeout (proxy,
 		                                      "SendPin", stage1_pin_done,
 		                                      self, NULL, 10000,
@@ -387,6 +390,14 @@ create_connect_properties (NMConnection *connection)
 		value_hash_add_uint (properties, "network_mode", MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_2G_PREFERRED);
 		value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED);
 		break;
+	case NM_SETTING_GSM_NETWORK_TYPE_PREFER_4G:
+		/* deprecated modes not extended for 4G, so no need to set them here */
+		value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_4G_PREFERRED);
+		break;
+	case NM_SETTING_GSM_NETWORK_TYPE_4G:
+		/* deprecated modes not extended for 4G, so no need to set them here */
+		value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_4G_ONLY);
+		break;
 	default:
 		value_hash_add_uint (properties, "network_mode", MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_ANY);
 		value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_ANY);
@@ -423,11 +434,11 @@ create_connect_properties (NMConnection *connection)
 }
 
 static NMActStageReturn
-real_act_stage1_prepare (NMModem *modem,
-                         NMActRequest *req,
-                         GPtrArray **out_hints,
-                         const char **out_setting_name,
-                         NMDeviceStateReason *reason)
+act_stage1_prepare (NMModem *modem,
+                    NMActRequest *req,
+                    GPtrArray **out_hints,
+                    const char **out_setting_name,
+                    NMDeviceStateReason *reason)
 {
 	NMModemGsm *self = NM_MODEM_GSM (modem);
 	NMModemGsmPrivate *priv = NM_MODEM_GSM_GET_PRIVATE (self);
@@ -456,9 +467,9 @@ real_act_stage1_prepare (NMModem *modem,
 }
 
 static NMConnection *
-real_get_best_auto_connection (NMModem *modem,
-							   GSList *connections,
-							   char **specific_object)
+get_best_auto_connection (NMModem *modem,
+                          GSList *connections,
+                          char **specific_object)
 {
 	GSList *iter;
 
@@ -481,9 +492,9 @@ real_get_best_auto_connection (NMModem *modem,
 }
 
 static gboolean
-real_check_connection_compatible (NMModem *modem,
-                                  NMConnection *connection,
-                                  GError **error)
+check_connection_compatible (NMModem *modem,
+                             NMConnection *connection,
+                             GError **error)
 {
 	NMSettingConnection *s_con;
 	NMSettingGsm *s_gsm;
@@ -510,10 +521,10 @@ real_check_connection_compatible (NMModem *modem,
 }
 
 static gboolean
-real_complete_connection (NMModem *modem,
-                          NMConnection *connection,
-                          const GSList *existing_connections,
-                          GError **error)
+complete_connection (NMModem *modem,
+                     NMConnection *connection,
+                     const GSList *existing_connections,
+                     GError **error)
 {
 	NMSettingGsm *s_gsm;
 	NMSettingPPP *s_ppp;
@@ -552,10 +563,10 @@ real_complete_connection (NMModem *modem,
 }
 
 static gboolean
-real_get_user_pass (NMModem *modem,
-                    NMConnection *connection,
-                    const char **user,
-                    const char **pass)
+get_user_pass (NMModem *modem,
+               NMConnection *connection,
+               const char **user,
+               const char **pass)
 {
 	NMSettingGsm *s_gsm;
 
@@ -572,20 +583,20 @@ real_get_user_pass (NMModem *modem,
 }
 
 static const char *
-real_get_setting_name (NMModem *modem)
+get_setting_name (NMModem *modem)
 {
 	return NM_SETTING_GSM_SETTING_NAME;
 }
 
 static void
-real_deactivate (NMModem *modem, NMDevice *device)
+deactivate (NMModem *modem, NMDevice *device)
 {
 	NMModemGsmPrivate *priv = NM_MODEM_GSM_GET_PRIVATE (modem);
 
 	if (priv->call) {
 		DBusGProxy *proxy;
 
-		proxy = nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM_SIMPLE);
+		proxy = nm_modem_generic_get_proxy (NM_MODEM_GENERIC (modem), MM_OLD_DBUS_INTERFACE_MODEM_SIMPLE);
 		dbus_g_proxy_cancel_call (proxy, priv->call);
 		priv->call = NULL;
 	}
@@ -630,13 +641,13 @@ nm_modem_gsm_class_init (NMModemGsmClass *klass)
 
 	/* Virtual methods */
 	object_class->dispose = dispose;
-	modem_class->get_user_pass = real_get_user_pass;
-	modem_class->get_setting_name = real_get_setting_name;
-	modem_class->get_best_auto_connection = real_get_best_auto_connection;
-	modem_class->check_connection_compatible = real_check_connection_compatible;
-	modem_class->complete_connection = real_complete_connection;
-	modem_class->act_stage1_prepare = real_act_stage1_prepare;
-	modem_class->deactivate = real_deactivate;
+	modem_class->get_user_pass = get_user_pass;
+	modem_class->get_setting_name = get_setting_name;
+	modem_class->get_best_auto_connection = get_best_auto_connection;
+	modem_class->check_connection_compatible = check_connection_compatible;
+	modem_class->complete_connection = complete_connection;
+	modem_class->act_stage1_prepare = act_stage1_prepare;
+	modem_class->deactivate = deactivate;
 
 	dbus_g_error_domain_register (NM_GSM_ERROR, NULL, NM_TYPE_GSM_ERROR);
 }
diff --git a/src/modem-manager/nm-modem-gsm.h b/src/modem-manager/nm-modem-gsm.h
index e1c94f04..b0f78b0a 100644
--- a/src/modem-manager/nm-modem-gsm.h
+++ b/src/modem-manager/nm-modem-gsm.h
@@ -22,16 +22,16 @@
 #ifndef NM_MODEM_GSM_H
 #define NM_MODEM_GSM_H
 
-#include <nm-modem.h>
+#include <nm-modem-generic.h>
 
 G_BEGIN_DECLS
 
-#define NM_TYPE_MODEM_GSM			 (nm_modem_gsm_get_type ())
-#define NM_MODEM_GSM(obj)			 (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_GSM, NMModemGsm))
-#define NM_MODEM_GSM_CLASS(klass)	 (G_TYPE_CHECK_CLASS_CAST ((klass),	 NM_TYPE_MODEM_GSM, NMModemGsmClass))
-#define NM_IS_MODEM_GSM(obj)		 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_GSM))
+#define NM_TYPE_MODEM_GSM            (nm_modem_gsm_get_type ())
+#define NM_MODEM_GSM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_GSM, NMModemGsm))
+#define NM_MODEM_GSM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),	 NM_TYPE_MODEM_GSM, NMModemGsmClass))
+#define NM_IS_MODEM_GSM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_GSM))
 #define NM_IS_MODEM_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),	 NM_TYPE_MODEM_GSM))
-#define NM_MODEM_GSM_GET_CLASS(obj)	 (G_TYPE_INSTANCE_GET_CLASS ((obj),	 NM_TYPE_MODEM_GSM, NMModemGsmClass))
+#define NM_MODEM_GSM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),	 NM_TYPE_MODEM_GSM, NMModemGsmClass))
 
 typedef enum {
 	NM_GSM_ERROR_CONNECTION_NOT_GSM = 0,  /*< nick=ConnectionNotGsm >*/
@@ -40,22 +40,19 @@ typedef enum {
 } NMGsmError;
 
 typedef struct {
-	NMModem parent;
+	NMModemGeneric parent;
 } NMModemGsm;
 
 typedef struct {
-	NMModemClass parent;
-
-	/* Signals */
-	void (*signal_quality) (NMModemGsm *self, guint32 quality);
+	NMModemGenericClass parent;
 } NMModemGsmClass;
 
 GType nm_modem_gsm_get_type (void);
 
 NMModem *nm_modem_gsm_new (const char *path,
-                           const char *device,
                            const char *data_device,
-                           guint32 ip_method);
+                           guint32 ip_method,
+                           NMModemState state);
 
 G_END_DECLS
 
diff --git a/src/modem-manager/nm-modem-manager.c b/src/modem-manager/nm-modem-manager.c
index 051940f5..d896b468 100644
--- a/src/modem-manager/nm-modem-manager.c
+++ b/src/modem-manager/nm-modem-manager.c
@@ -21,6 +21,7 @@
  */
 
 #include <string.h>
+#include "config.h"
 #include "nm-modem-manager.h"
 #include "nm-logging.h"
 #include "nm-modem.h"
@@ -31,19 +32,33 @@
 #include "nm-marshal.h"
 #include "nm-dbus-glib-types.h"
 
+#if WITH_MODEM_MANAGER_1
+#include <libmm-glib.h>
+#include "nm-modem-broadband.h"
+#endif
+
 #define MODEM_POKE_INTERVAL 120
 
 G_DEFINE_TYPE (NMModemManager, nm_modem_manager, G_TYPE_OBJECT)
 
-#define NM_MODEM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM_MANAGER, NMModemManagerPrivate))
-
-typedef struct {
+struct _NMModemManagerPrivate {
+	/* ModemManager < 0.7 */
 	NMDBusManager *dbus_mgr;
 	DBusGProxy *proxy;
-	GHashTable *modems;
-	gboolean disposed;
 	guint poke_id;
-} NMModemManagerPrivate;
+
+#if WITH_MODEM_MANAGER_1
+	/* ModemManager >= 0.7 */
+	GDBusConnection *dbus_connection;
+	MMManager *modem_manager_1;
+	guint modem_manager_1_poke_id;
+	gboolean old_modem_manager_found;
+	gboolean new_modem_manager_found;
+#endif
+
+	/* Common */
+	GHashTable *modems;
+};
 
 enum {
 	MODEM_ADDED,
@@ -69,6 +84,28 @@ nm_modem_manager_get (void)
 	return singleton;
 }
 
+/************************************************************************/
+/* Support for ModemManager < 0.7 */
+
+static void
+clear_modem_manager_support (NMModemManager *self)
+{
+	if (self->priv->poke_id) {
+		g_source_remove (self->priv->poke_id);
+		self->priv->poke_id = 0;
+	}
+
+	if (self->priv->proxy) {
+		g_object_unref (self->priv->proxy);
+		self->priv->proxy = NULL;
+	}
+
+	if (self->priv->dbus_mgr) {
+		g_object_unref (self->priv->dbus_mgr);
+		self->priv->dbus_mgr = NULL;
+	}
+}
+
 static gboolean
 get_modem_properties (DBusGConnection *connection,
 					  const char *path,
@@ -77,7 +114,8 @@ get_modem_properties (DBusGConnection *connection,
 					  char **driver,
 					  guint32 *type,
 					  guint32 *ip_method,
-					  guint32 *ip_timeout)
+					  guint32 *ip_timeout,
+					  NMModemState *state)
 {
 	DBusGProxy *proxy;
 	GError *err = NULL;
@@ -87,12 +125,12 @@ get_modem_properties (DBusGConnection *connection,
 	GValue *value;
 
 	proxy = dbus_g_proxy_new_for_name (connection,
-	                                   MM_DBUS_SERVICE,
+	                                   MM_OLD_DBUS_SERVICE,
 	                                   path,
 	                                   "org.freedesktop.DBus.Properties");
 
 	if (!dbus_g_proxy_call_with_timeout (proxy, "GetAll", 15000, &err,
-	                                     G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
+	                                     G_TYPE_STRING, MM_OLD_DBUS_INTERFACE_MODEM,
 	                                     G_TYPE_INVALID,
 	                                     DBUS_TYPE_G_MAP_OF_VARIANT, &props,
 	                                     G_TYPE_INVALID)) {
@@ -122,6 +160,8 @@ get_modem_properties (DBusGConnection *connection,
 			*driver = g_value_dup_string (value);
 		else if (g_strcmp0 (prop, "IpTimeout") == 0)
 			*ip_timeout = g_value_get_uint (value);
+		else if (g_strcmp0 (prop, "State") == 0)
+			*state = g_value_get_uint (value);
 	}
 	g_hash_table_unref (props);
 
@@ -132,23 +172,23 @@ get_modem_properties (DBusGConnection *connection,
 }
 
 static void
-create_modem (NMModemManager *manager, const char *path)
+create_modem (NMModemManager *self, const char *path)
 {
-	NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (manager);
 	NMModem *modem = NULL;
 	char *data_device = NULL, *driver = NULL, *master_device = NULL;
 	uint modem_type = MM_MODEM_TYPE_UNKNOWN;
 	uint ip_method = MM_MODEM_IP_METHOD_PPP;
 	uint ip_timeout = 0;
+	NMModemState state = NM_MODEM_STATE_UNKNOWN;
 
-	if (g_hash_table_lookup (priv->modems, path)) {
+	if (g_hash_table_lookup (self->priv->modems, path)) {
 		nm_log_warn (LOGD_MB, "modem with path %s already exists, ignoring", path);
 		return;
 	}
 
-	if (!get_modem_properties (nm_dbus_manager_get_connection (priv->dbus_mgr),
+	if (!get_modem_properties (nm_dbus_manager_get_connection (self->priv->dbus_mgr),
 	                           path, &master_device, &data_device, &driver,
-	                           &modem_type, &ip_method, &ip_timeout))
+	                           &modem_type, &ip_method, &ip_timeout, &state))
 		return;
 
 	if (modem_type == MM_MODEM_TYPE_UNKNOWN) {
@@ -172,9 +212,9 @@ create_modem (NMModemManager *manager, const char *path)
 	}
 
 	if (modem_type == MM_MODEM_TYPE_GSM)
-		modem = nm_modem_gsm_new (path, master_device, data_device, ip_method);
+		modem = nm_modem_gsm_new (path, data_device, ip_method, state);
 	else if (modem_type == MM_MODEM_TYPE_CDMA)
-		modem = nm_modem_cdma_new (path, master_device, data_device, ip_method);
+		modem = nm_modem_cdma_new (path, data_device, ip_method, state);
 	else
 		nm_log_warn (LOGD_MB, "unknown modem type '%d'", modem_type);
 
@@ -182,8 +222,8 @@ create_modem (NMModemManager *manager, const char *path)
 
 	if (modem) {
 		g_object_set (G_OBJECT (modem), NM_MODEM_IP_TIMEOUT, ip_timeout, NULL);
-		g_hash_table_insert (priv->modems, g_strdup (path), modem);
-		g_signal_emit (manager, signals[MODEM_ADDED], 0, modem, driver);
+		g_hash_table_insert (self->priv->modems, g_strdup (path), modem);
+		g_signal_emit (self, signals[MODEM_ADDED], 0, modem, driver);
 	}
 
 	g_free (driver);
@@ -198,13 +238,13 @@ modem_added (DBusGProxy *proxy, const char *path, gpointer user_data)
 static void
 modem_removed (DBusGProxy *proxy, const char *path, gpointer user_data)
 {
-	NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (user_data);
+	NMModemManager *self = NM_MODEM_MANAGER (user_data);
 	NMModem *modem;
 
-	modem = (NMModem *) g_hash_table_lookup (priv->modems, path);
+	modem = (NMModem *) g_hash_table_lookup (self->priv->modems, path);
 	if (modem) {
-		g_signal_emit (user_data, signals[MODEM_REMOVED], 0, modem);
-		g_hash_table_remove (priv->modems, path);
+		g_signal_emit (self, signals[MODEM_REMOVED], 0, modem);
+		g_hash_table_remove (self->priv->modems, path);
 	}
 }
 
@@ -229,16 +269,17 @@ static gboolean
 poke_modem_cb (gpointer user_data)
 {
 	NMModemManager *self = NM_MODEM_MANAGER (user_data);
-	NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self);
 	DBusGConnection *g_connection;
 	DBusGProxy *proxy;
 	DBusGProxyCall *call;
 
-	g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
+	g_connection = nm_dbus_manager_get_connection (self->priv->dbus_mgr);
 	proxy = dbus_g_proxy_new_for_name (g_connection,
-									   MM_DBUS_SERVICE,
-									   MM_DBUS_PATH,
-									   MM_DBUS_INTERFACE);
+									   MM_OLD_DBUS_SERVICE,
+									   MM_OLD_DBUS_PATH,
+									   MM_OLD_DBUS_INTERFACE);
+
+	nm_log_dbg (LOGD_MB, "Requesting to (re)launch modem-manager...");
 
 	call = dbus_g_proxy_begin_call_with_timeout (proxy,
 	                                             "EnumerateDevices",
@@ -276,33 +317,43 @@ enumerate_devices_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer dat
 	}
 }
 
+#if WITH_MODEM_MANAGER_1
+static void clear_modem_manager_1_support (NMModemManager *self);
+#endif
+
 static void
 modem_manager_appeared (NMModemManager *self, gboolean enumerate_devices)
 {
-	NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self);
-
-	if (priv->poke_id) {
-		g_source_remove (priv->poke_id);
-		priv->poke_id = 0;
+	if (self->priv->poke_id) {
+		g_source_remove (self->priv->poke_id);
+		self->priv->poke_id = 0;
 	}
 
 	nm_log_info (LOGD_MB, "modem-manager is now available");
 
-	priv->proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
-											 MM_DBUS_SERVICE, MM_DBUS_PATH, MM_DBUS_INTERFACE);
+#if WITH_MODEM_MANAGER_1
+	self->priv->old_modem_manager_found = TRUE;
+	if (self->priv->new_modem_manager_found)
+		nm_log_warn (LOGD_MB, "Both the old and the new ModemManager were found");
+	else
+		clear_modem_manager_1_support (self);
+#endif
+
+	self->priv->proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (self->priv->dbus_mgr),
+	                                               MM_OLD_DBUS_SERVICE, MM_OLD_DBUS_PATH, MM_OLD_DBUS_INTERFACE);
 
-	dbus_g_proxy_add_signal (priv->proxy, "DeviceAdded", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->proxy, "DeviceAdded",
+	dbus_g_proxy_add_signal (self->priv->proxy, "DeviceAdded", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (self->priv->proxy, "DeviceAdded",
 								 G_CALLBACK (modem_added), self,
 								 NULL);
 
-	dbus_g_proxy_add_signal (priv->proxy, "DeviceRemoved", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->proxy, "DeviceRemoved",
+	dbus_g_proxy_add_signal (self->priv->proxy, "DeviceRemoved", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (self->priv->proxy, "DeviceRemoved",
 								 G_CALLBACK (modem_removed), self,
 								 NULL);
 
 	if (enumerate_devices)
-		dbus_g_proxy_begin_call (priv->proxy, "EnumerateDevices", enumerate_devices_done, self, NULL, G_TYPE_INVALID);
+		dbus_g_proxy_begin_call (self->priv->proxy, "EnumerateDevices", enumerate_devices_done, self, NULL, G_TYPE_INVALID);
 }
 
 static gboolean
@@ -316,19 +367,17 @@ remove_one_modem (gpointer key, gpointer value, gpointer user_data)
 static void
 modem_manager_disappeared (NMModemManager *self)
 {
-	NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self);
-
-	g_hash_table_foreach_remove (priv->modems, remove_one_modem, self);
+	g_hash_table_foreach_remove (self->priv->modems, remove_one_modem, self);
 
-	if (priv->proxy) {
-		g_object_unref (priv->proxy);
-		priv->proxy = NULL;
+	if (self->priv->proxy) {
+		g_object_unref (self->priv->proxy);
+		self->priv->proxy = NULL;
 	}
 
 	/* Try to activate the modem-manager */
-	nm_log_info (LOGD_MB, "trying to start the modem manager...");
+	nm_log_dbg (LOGD_MB, "trying to start the modem manager...");
 	poke_modem_cb (self);
-	priv->poke_id = g_timeout_add_seconds (MODEM_POKE_INTERVAL, poke_modem_cb, self);
+	self->priv->poke_id = g_timeout_add_seconds (MODEM_POKE_INTERVAL, poke_modem_cb, self);
 }
 
 static void
@@ -342,7 +391,7 @@ nm_modem_manager_name_owner_changed (NMDBusManager *dbus_mgr,
 	gboolean new_owner_good;
 
 	/* Can't handle the signal if its not from the modem service */
-	if (strcmp (MM_DBUS_SERVICE, name) != 0)
+	if (strcmp (MM_OLD_DBUS_SERVICE, name) != 0)
 		return;
 
 	old_owner_good = (old_owner && strlen (old_owner));
@@ -356,52 +405,306 @@ nm_modem_manager_name_owner_changed (NMDBusManager *dbus_mgr,
 	}
 }
 
-/*******************************************************/
+/************************************************************************/
+/* Support for ModemManager >= 0.7 */
+
+#if WITH_MODEM_MANAGER_1
 
 static void
-nm_modem_manager_init (NMModemManager *self)
+clear_modem_manager_1_support (NMModemManager *self)
 {
-	NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self);
+	if (self->priv->modem_manager_1_poke_id) {
+		g_source_remove (self->priv->modem_manager_1_poke_id);
+		self->priv->modem_manager_1_poke_id = 0;
+	}
 
-	priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
-	priv->dbus_mgr = nm_dbus_manager_get ();
+	g_clear_object (&self->priv->modem_manager_1);
+	g_clear_object (&self->priv->dbus_connection);
+}
 
-	g_signal_connect (priv->dbus_mgr, NM_DBUS_MANAGER_NAME_OWNER_CHANGED,
-					  G_CALLBACK (nm_modem_manager_name_owner_changed),
-					  self);
+static void
+modem_object_added (MMManager *modem_manager,
+                    MMObject  *modem_object,
+                    NMModemManager *self)
+{
+	const gchar *path;
+	gchar *drivers;
+	MMModem *modem_iface;
+	NMModem *modem;
 
-	if (nm_dbus_manager_name_has_owner (priv->dbus_mgr, MM_DBUS_SERVICE))
-		modem_manager_appeared (self, TRUE);
+	/* Ensure we don't have the same modem already */
+	path = mm_object_get_path (modem_object);
+	if (g_hash_table_lookup (self->priv->modems, path)) {
+		nm_log_warn (LOGD_MB, "modem with path %s already exists, ignoring", path);
+		return;
+	}
+
+	/* Ensure we have the 'Modem' interface at least */
+	modem_iface = mm_object_peek_modem (modem_object);
+	if (!modem_iface) {
+		nm_log_warn (LOGD_MB, "modem with path %s doesn't have the Modem interface, ignoring", path);
+		return;
+	}
+
+	/* Ensure we have a primary port reported */
+	if (!mm_modem_get_primary_port (modem_iface)) {
+		nm_log_warn (LOGD_MB, "modem with path %s has unknown primary port, ignoring", path);
+		return;
+	}
+
+	/* Create a new modem object */
+	modem = nm_modem_broadband_new (G_OBJECT (modem_object));
+	if (!modem)
+		return;
+
+	/* Build a single string with all drivers listed */
+	drivers = g_strjoinv (", ", (gchar **)mm_modem_get_drivers (modem_iface));
+
+	/* Keep track of the new modem and notify about it */
+	g_hash_table_insert (self->priv->modems, g_strdup (path), modem);
+	g_signal_emit (self, signals[MODEM_ADDED], 0, modem, drivers);
+	g_free (drivers);
+}
+
+static void
+modem_object_removed (MMManager *manager,
+                      MMObject  *modem_object,
+                      NMModemManager *self)
+{
+	NMModem *modem;
+	const gchar *path;
+
+	path = mm_object_get_path (modem_object);
+	modem = (NMModem *) g_hash_table_lookup (self->priv->modems, path);
+	if (!modem)
+		return;
+
+	g_signal_emit (self, signals[MODEM_REMOVED], 0, modem);
+	g_hash_table_remove (self->priv->modems, path);
+}
+
+static void
+modem_manager_1_available (NMModemManager *self)
+{
+	GList *modems, *l;
+
+	nm_log_info (LOGD_MB, "ModemManager available in the bus");
+
+	self->priv->new_modem_manager_found = TRUE;
+	if (self->priv->old_modem_manager_found)
+		nm_log_warn (LOGD_MB, "Both the old and the new ModemManager were found");
 	else
-		modem_manager_disappeared (self);
+		clear_modem_manager_support (self);
+
+	/* Update initial modems list */
+    modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->priv->modem_manager_1));
+    for (l = modems; l; l = g_list_next (l))
+	    modem_object_added (self->priv->modem_manager_1, MM_OBJECT (l->data), self);
+    g_list_free_full (modems, (GDestroyNotify) g_object_unref);
 }
 
+static void schedule_modem_manager_1_relaunch (NMModemManager *self,
+                                               guint n_seconds);
+
 static void
-dispose (GObject *object)
+modem_manager_1_name_owner_changed (MMManager *modem_manager_1,
+                                    GParamSpec *pspec,
+                                    NMModemManager *self)
 {
-	NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (object);
+	/* Quit poking, if any */
+	if (self->priv->modem_manager_1_poke_id) {
+		g_source_remove (self->priv->modem_manager_1_poke_id);
+		self->priv->modem_manager_1_poke_id = 0;
+	}
 
-	if (priv->disposed)
+	if (!g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (modem_manager_1))) {
+		nm_log_info (LOGD_MB, "ModemManager disappeared from bus");
+		schedule_modem_manager_1_relaunch (self, 0);
 		return;
+	}
+
+	/* Available! */
+	modem_manager_1_available (self);
+}
+
+static void
+manager_new_ready (GObject *source,
+                   GAsyncResult *res,
+                   NMModemManager *self)
+{
+	/* Note we always get an extra reference to self here */
 
-	priv->disposed = TRUE;
+	GError *error = NULL;
 
-	if (priv->poke_id) {
-		g_source_remove (priv->poke_id);
-		priv->poke_id = 0;
+	g_assert (!self->priv->modem_manager_1);
+	self->priv->modem_manager_1 = mm_manager_new_finish (res, &error);
+	if (!self->priv->modem_manager_1) {
+		if (   !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)
+		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_EXEC_FAILED)
+		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FORK_FAILED)
+		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FAILED)
+		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_TIMEOUT)
+		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) {
+			nm_log_warn (LOGD_MB, "error creating ModemManager client: %s", error->message);
+		}
+		g_error_free (error);
+		/* Setup timeout to relaunch */
+		schedule_modem_manager_1_relaunch (self, MODEM_POKE_INTERVAL);
+	} else if (self->priv->old_modem_manager_found) {
+		/* If we found the old MM, abort */
+		clear_modem_manager_1_support (self);
+	} else {
+		gchar *name_owner;
+
+		g_signal_connect (self->priv->modem_manager_1,
+		                  "notify::name-owner",
+		                  G_CALLBACK (modem_manager_1_name_owner_changed),
+		                  self);
+		g_signal_connect (self->priv->modem_manager_1,
+		                  "object-added",
+		                  G_CALLBACK (modem_object_added),
+		                  self);
+		g_signal_connect (self->priv->modem_manager_1,
+		                  "object-removed",
+		                  G_CALLBACK (modem_object_removed),
+		                  self);
+
+		/* If there is no current owner right away, ensure we poke until we get
+		 * one */
+		name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (self->priv->modem_manager_1));
+		if (!name_owner) {
+			/* Setup timeout to wait for an owner */
+			schedule_modem_manager_1_relaunch (self, MODEM_POKE_INTERVAL);
+		} else {
+			/* Available! */
+			modem_manager_1_available (self);
+			g_free (name_owner);
+		}
 	}
 
-	g_hash_table_foreach_remove (priv->modems, remove_one_modem, object);
-	g_hash_table_destroy (priv->modems);
+	/* Balance refcount */
+	g_object_unref (self);
+}
+
+static void
+recreate_client (NMModemManager *self)
+{
+	g_assert (self->priv->dbus_connection);
+
+	/* Re-create the GDBusObjectManagerClient so that we request again the owner
+	 * for the well-known name.
+	 * Note that we pass an extra reference always */
+	g_clear_object (&self->priv->modem_manager_1);
+	mm_manager_new (self->priv->dbus_connection,
+	                G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+	                NULL,
+	                (GAsyncReadyCallback)manager_new_ready,
+	                g_object_ref (self));
+}
+
+static void
+bus_get_ready (GObject *source,
+               GAsyncResult *res,
+               NMModemManager *self)
+{
+	/* Note we always get an extra reference to self here */
+
+	GError *error = NULL;
 
-	if (priv->proxy) {
-		g_object_unref (priv->proxy);
-		priv->proxy = NULL;
+	self->priv->dbus_connection = g_bus_get_finish (res, &error);
+	if (!self->priv->dbus_connection) {
+		nm_log_warn (LOGD_CORE, "error getting bus connection: %s", error->message);
+		g_error_free (error);
+		/* Setup timeout to relaunch */
+		schedule_modem_manager_1_relaunch (self, MODEM_POKE_INTERVAL);
+	} else if (self->priv->old_modem_manager_found) {
+		/* If we found the old MM, abort */
+		clear_modem_manager_1_support (self);
+	} else {
+		/* Got the bus, create new ModemManager client. */
+		recreate_client (self);
 	}
 
-	if (priv->dbus_mgr) {
-		g_object_unref (priv->dbus_mgr);
-		priv->dbus_mgr = NULL;
+	/* Balance refcount */
+	g_object_unref (self);
+}
+
+static gboolean
+ensure_bus (NMModemManager *self)
+{
+	nm_log_dbg (LOGD_MB, "Requesting to (re)launch ModemManager...");
+
+	/* Clear poke ID */
+	self->priv->modem_manager_1_poke_id = 0;
+
+	if (!self->priv->dbus_connection)
+		g_bus_get (G_BUS_TYPE_SYSTEM,
+		           NULL,
+		           (GAsyncReadyCallback)bus_get_ready,
+		           g_object_ref (self));
+	else
+		/* If bus is already available, launch client re-creation */
+		recreate_client (self);
+
+	return FALSE;
+}
+
+static void
+schedule_modem_manager_1_relaunch (NMModemManager *self,
+                                   guint n_seconds)
+{
+	/* No need to pass an extra reference to self; timeout/idle will be
+	 * cancelled if the object gets disposed. */
+
+	if (n_seconds)
+		self->priv->modem_manager_1_poke_id = g_timeout_add_seconds (n_seconds, (GSourceFunc)ensure_bus, self);
+	else
+		self->priv->modem_manager_1_poke_id = g_idle_add ((GSourceFunc)ensure_bus, self);
+}
+
+#endif /* WITH_MODEM_MANAGER_1 */
+
+/************************************************************************/
+
+static void
+nm_modem_manager_init (NMModemManager *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_MODEM_MANAGER, NMModemManagerPrivate);
+
+	self->priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+
+	/* ModemManager < 0.7 */
+	self->priv->dbus_mgr = nm_dbus_manager_get ();
+	g_signal_connect (self->priv->dbus_mgr, NM_DBUS_MANAGER_NAME_OWNER_CHANGED,
+					  G_CALLBACK (nm_modem_manager_name_owner_changed),
+					  self);
+	if (nm_dbus_manager_name_has_owner (self->priv->dbus_mgr, MM_OLD_DBUS_SERVICE))
+		modem_manager_appeared (self, TRUE);
+	else
+		modem_manager_disappeared (self);
+
+#if WITH_MODEM_MANAGER_1
+	/* ModemManager >= 0.7 */
+	schedule_modem_manager_1_relaunch (self, 0);
+#endif
+}
+
+static void
+dispose (GObject *object)
+{
+	NMModemManager *self = NM_MODEM_MANAGER (object);
+
+	/* ModemManager < 0.7 */
+	clear_modem_manager_support (self);
+
+#if WITH_MODEM_MANAGER_1
+	/* ModemManager >= 0.7 */
+	clear_modem_manager_1_support (self);
+#endif
+
+	if (self->priv->modems) {
+		g_hash_table_foreach_remove (self->priv->modems, remove_one_modem, object);
+		g_hash_table_destroy (self->priv->modems);
 	}
 
 	/* Chain up to the parent class */
diff --git a/src/modem-manager/nm-modem-manager.h b/src/modem-manager/nm-modem-manager.h
index 56427baf..0c2b243b 100644
--- a/src/modem-manager/nm-modem-manager.h
+++ b/src/modem-manager/nm-modem-manager.h
@@ -33,18 +33,23 @@
 #define NM_IS_MODEM_MANAGER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass),	NM_TYPE_MODEM_MANAGER))
 #define NM_MODEM_MANAGER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj),	NM_TYPE_MODEM_MANAGER, NMModemManagerClass))
 
-typedef struct {
+typedef struct _NMModemManager NMModemManager;
+typedef struct _NMModemManagerClass NMModemManagerClass;
+typedef struct _NMModemManagerPrivate NMModemManagerPrivate;
+
+struct _NMModemManager {
 	GObject parent;
-} NMModemManager;
+	NMModemManagerPrivate *priv;
+};
 
-typedef struct {
+struct _NMModemManagerClass {
 	GObjectClass parent;
 
 	/* Signals */
 	void (*modem_added) (NMModemManager *manager, NMModem *modem, const char *driver);
 
 	void (*modem_removed) (NMModemManager *manager, NMModem *modem);
-} NMModemManagerClass;
+};
 
 GType nm_modem_manager_get_type (void);
 
diff --git a/src/modem-manager/nm-modem-types.h b/src/modem-manager/nm-modem-types.h
index e805cb21..9fc8deed 100644
--- a/src/modem-manager/nm-modem-types.h
+++ b/src/modem-manager/nm-modem-types.h
@@ -21,37 +21,32 @@
 #ifndef NM_MODEM_TYPES_H
 #define NM_MODEM_TYPES_H
 
-#define MM_DBUS_SERVICE              "org.freedesktop.ModemManager"
-#define MM_DBUS_PATH                 "/org/freedesktop/ModemManager"
-#define MM_DBUS_INTERFACE            "org.freedesktop.ModemManager"
-#define MM_DBUS_INTERFACE_MODEM      "org.freedesktop.ModemManager.Modem"
-#define MM_DBUS_INTERFACE_MODEM_SIMPLE "org.freedesktop.ModemManager.Modem.Simple"
-#define MM_DBUS_INTERFACE_MODEM_CDMA "org.freedesktop.ModemManager.Modem.Cdma"
-
-#define MM_DBUS_INTERFACE_MODEM_GSM_CARD    "org.freedesktop.ModemManager.Modem.Gsm.Card"
-#define MM_DBUS_INTERFACE_MODEM_GSM_NETWORK "org.freedesktop.ModemManager.Modem.Gsm.Network"
+#define MM_OLD_DBUS_SERVICE                     "org.freedesktop.ModemManager"
+#define MM_OLD_DBUS_PATH                        "/org/freedesktop/ModemManager"
+#define MM_OLD_DBUS_INTERFACE                   "org.freedesktop.ModemManager"
+#define MM_OLD_DBUS_INTERFACE_MODEM             "org.freedesktop.ModemManager.Modem"
+#define MM_OLD_DBUS_INTERFACE_MODEM_SIMPLE      "org.freedesktop.ModemManager.Modem.Simple"
+#define MM_OLD_DBUS_INTERFACE_MODEM_CDMA        "org.freedesktop.ModemManager.Modem.Cdma"
+#define MM_OLD_DBUS_INTERFACE_MODEM_GSM_CARD    "org.freedesktop.ModemManager.Modem.Gsm.Card"
+#define MM_OLD_DBUS_INTERFACE_MODEM_GSM_NETWORK "org.freedesktop.ModemManager.Modem.Gsm.Network"
 
 #define MM_MODEM_TYPE_UNKNOWN  0
 #define MM_MODEM_TYPE_GSM      1
 #define MM_MODEM_TYPE_CDMA     2
 
-#define MM_MODEM_IP_METHOD_PPP    0
-#define MM_MODEM_IP_METHOD_STATIC 1
-#define MM_MODEM_IP_METHOD_DHCP   2
-
 /* Errors */
 
-#define MM_SERIAL_OPEN_FAILED MM_DBUS_INTERFACE_MODEM ".SerialOpenFailed"
-#define MM_SERIAL_SEND_FAILED MM_DBUS_INTERFACE_MODEM ".SerialSendFailed"
-#define MM_SERIAL_RESPONSE_TIMEOUT MM_DBUS_INTERFACE_MODEM ".SerialResponseTimeout"
+#define MM_SERIAL_OPEN_FAILED MM_OLD_DBUS_INTERFACE_MODEM ".SerialOpenFailed"
+#define MM_SERIAL_SEND_FAILED MM_OLD_DBUS_INTERFACE_MODEM ".SerialSendFailed"
+#define MM_SERIAL_RESPONSE_TIMEOUT MM_OLD_DBUS_INTERFACE_MODEM ".SerialResponseTimeout"
 
-#define MM_MODEM_ERROR_GENERAL MM_DBUS_INTERFACE_MODEM ".General"
-#define MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED MM_DBUS_INTERFACE_MODEM ".OperationNotSupported"
+#define MM_MODEM_ERROR_GENERAL MM_OLD_DBUS_INTERFACE_MODEM ".General"
+#define MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED MM_OLD_DBUS_INTERFACE_MODEM ".OperationNotSupported"
 
-#define MM_MODEM_CONNECT_ERROR_NO_CARRIER MM_DBUS_INTERFACE_MODEM ".NoCarrier"
-#define MM_MODEM_CONNECT_ERROR_NO_DIALTONE MM_DBUS_INTERFACE_MODEM ".NoDialtone"
-#define MM_MODEM_CONNECT_ERROR_BUSY MM_DBUS_INTERFACE_MODEM ".Busy"
-#define MM_MODEM_CONNECT_ERROR_NO_ANSWER MM_DBUS_INTERFACE_MODEM ".NoAnswer"
+#define MM_MODEM_CONNECT_ERROR_NO_CARRIER MM_OLD_DBUS_INTERFACE_MODEM ".NoCarrier"
+#define MM_MODEM_CONNECT_ERROR_NO_DIALTONE MM_OLD_DBUS_INTERFACE_MODEM ".NoDialtone"
+#define MM_MODEM_CONNECT_ERROR_BUSY MM_OLD_DBUS_INTERFACE_MODEM ".Busy"
+#define MM_MODEM_CONNECT_ERROR_NO_ANSWER MM_OLD_DBUS_INTERFACE_MODEM ".NoAnswer"
 
 #define MM_MODEM_ERROR "org.freedesktop.ModemManager.Modem.Gsm"
 
diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c
index c43e5e16..2d24a3ea 100644
--- a/src/modem-manager/nm-modem.c
+++ b/src/modem-manager/nm-modem.c
@@ -38,35 +38,34 @@ G_DEFINE_TYPE (NMModem, nm_modem, G_TYPE_OBJECT)
 
 enum {
 	PROP_0,
-	PROP_DEVICE,
-	PROP_IFACE,
+	PROP_CONTROL_PORT,
+	PROP_DATA_PORT,
 	PROP_PATH,
+	PROP_UID,
 	PROP_IP_METHOD,
 	PROP_IP_TIMEOUT,
 	PROP_ENABLED,
+	PROP_CONNECTED,
 
 	LAST_PROP
 };
 
 typedef struct {
-	NMDBusManager *dbus_mgr;
-	DBusGProxy *proxy;
-	DBusGProxy *props_proxy;
-
+	char *uid;
 	char *path;
-	NMPPPManager *ppp_manager;
+	char *control_port;
+	char *data_port;
 	guint32 ip_method;
-	char *device;
-	char *iface;
+
+	NMPPPManager *ppp_manager;
 
 	NMActRequest *act_request;
 	guint32 secrets_tries;
 	guint32 secrets_id;
 
-	DBusGProxyCall *call;
-
 	gboolean mm_enabled;
 	guint32 mm_ip_timeout;
+	gboolean mm_connected;
 
 	/* PPP stats */
 	guint32 in_bytes;
@@ -86,47 +85,31 @@ enum {
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
-static void
-update_mm_enabled (NMModem *self, gboolean new_enabled)
-{
-	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
-
-	if (priv->mm_enabled != new_enabled) {
-		priv->mm_enabled = new_enabled;
-		g_object_notify (G_OBJECT (self), NM_MODEM_ENABLED);
-	}
-}
+/*****************************************************************************/
+/* Get/Set enabled/connected */
 
 gboolean
 nm_modem_get_mm_enabled (NMModem *self)
 {
-	g_return_val_if_fail (NM_IS_MODEM (self), TRUE);
-
 	return NM_MODEM_GET_PRIVATE (self)->mm_enabled;
 }
 
-DBusGProxy *
-nm_modem_get_proxy (NMModem *self,
-					const char *interface)
+void
+nm_modem_set_mm_enabled (NMModem *self,
+                         gboolean enabled)
 {
+	NMModemPrivate *priv;
 
-	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
-	const char *current_iface;
-
-	g_return_val_if_fail (NM_IS_MODEM (self), NULL);
-
-	/* Default to the default interface. */
-	if (interface == NULL)
-		interface = MM_DBUS_INTERFACE_MODEM;
-
-	if (interface && !strcmp (interface, DBUS_INTERFACE_PROPERTIES))
-		return priv->props_proxy;
+	priv = NM_MODEM_GET_PRIVATE (self);
 
-	current_iface = dbus_g_proxy_get_interface (priv->proxy);
-	if (!current_iface || strcmp (current_iface, interface))
-		dbus_g_proxy_set_interface (priv->proxy, interface);
+	if (priv->mm_enabled != enabled)
+		NM_MODEM_GET_CLASS (self)->set_mm_enabled (self, enabled);
+}
 
-	return priv->proxy;
+gboolean
+nm_modem_get_mm_connected (NMModem *self)
+{
+	return NM_MODEM_GET_PRIVATE (self)->mm_connected;
 }
 
 /*****************************************************************************/
@@ -154,6 +137,7 @@ ppp_ip4_config (NMPPPManager *ppp_manager,
 				gpointer user_data)
 {
 	NMModem *self = NM_MODEM (user_data);
+	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
 	guint32 i, num;
 	guint32 bad_dns1 = htonl (0x0A0B0C0D);
 	guint32 good_dns1 = htonl (0x04020201);  /* GTE nameserver */
@@ -161,6 +145,11 @@ ppp_ip4_config (NMPPPManager *ppp_manager,
 	guint32 good_dns2 = htonl (0x04020202);  /* GTE nameserver */
 	gboolean dns_workaround = FALSE;
 
+	/* Notify about the new data port to use */
+	g_free (priv->data_port);
+	priv->data_port = g_strdup (iface);
+	g_object_notify (G_OBJECT (self), NM_MODEM_DATA_PORT);
+
 	/* Work around a PPP bug (#1732) which causes many mobile broadband
 	 * providers to return 10.11.12.13 and 10.11.12.14 for the DNS servers.
 	 * Apparently fixed in ppp-2.4.5 but we've had some reports that this is
@@ -197,7 +186,7 @@ ppp_ip4_config (NMPPPManager *ppp_manager,
 		nm_ip4_config_add_nameserver (config, good_dns2);
 	}
 
-	g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, iface, config, NULL);
+	g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, config, NULL);
 }
 
 static void
@@ -250,17 +239,17 @@ ppp_stage3_ip4_config_start (NMModem *self,
 		ip_timeout = priv->mm_ip_timeout;
 	}
 
-	priv->ppp_manager = nm_ppp_manager_new (priv->iface);
+	priv->ppp_manager = nm_ppp_manager_new (priv->data_port);
 	if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, ip_timeout, &error)) {
 		g_signal_connect (priv->ppp_manager, "state-changed",
-						  G_CALLBACK (ppp_state_changed),
-						  self);
+		                  G_CALLBACK (ppp_state_changed),
+		                  self);
 		g_signal_connect (priv->ppp_manager, "ip4-config",
-						  G_CALLBACK (ppp_ip4_config),
-						  self);
+		                  G_CALLBACK (ppp_ip4_config),
+		                  self);
 		g_signal_connect (priv->ppp_manager, "stats",
-						  G_CALLBACK (ppp_stats),
-						  self);
+		                  G_CALLBACK (ppp_stats),
+		                  self);
 
 		ret = NM_ACT_STAGE_RETURN_POSTPONE;
 	} else {
@@ -280,103 +269,6 @@ ppp_stage3_ip4_config_start (NMModem *self,
 }
 
 /*****************************************************************************/
-/* IP method static */
-
-static char addr_to_string_buf[INET6_ADDRSTRLEN + 1];
-
-static const char *
-ip_address_to_string (guint32 numeric)
-{
-	struct in_addr temp_addr;
-
-	memset (&addr_to_string_buf, '\0', sizeof (addr_to_string_buf));
-	temp_addr.s_addr = numeric;
-
-	if (inet_ntop (AF_INET, &temp_addr, addr_to_string_buf, INET_ADDRSTRLEN)) {
-		return addr_to_string_buf;
-	} else {
-		nm_log_warn (LOGD_VPN, "error converting IP4 address 0x%X",
-		             ntohl (temp_addr.s_addr));
-		return NULL;
-	}
-}
-
-static void
-static_stage3_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
-{
-	NMModem *self = NM_MODEM (user_data);
-	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
-	GValueArray *ret_array = NULL;
-	GError *error = NULL;
-	NMIP4Config *config = NULL;
-
-	priv->call = NULL;
-
-	/* Returned value array is (uuuu): [IP, DNS1, DNS2, DNS3], all in
-	 * network byte order.
-	 */
-	if (dbus_g_proxy_end_call (proxy, call, &error,
-	                           G_TYPE_VALUE_ARRAY, &ret_array,
-	                           G_TYPE_INVALID)) {
-		NMIP4Address *addr;
-		int i;
-
-		config = nm_ip4_config_new ();
-
-		addr = nm_ip4_address_new ();
-
-		nm_log_info (LOGD_MB, "(%s): IPv4 static configuration:", priv->iface);
-
-		/* IP address */
-		nm_ip4_address_set_address (addr, g_value_get_uint (g_value_array_get_nth (ret_array, 0)));
-		nm_ip4_address_set_prefix (addr, 32);
-		nm_ip4_config_take_address (config, addr);
-
-		nm_log_info (LOGD_MB, "  address %s/%d",
-		             ip_address_to_string (nm_ip4_address_get_address (addr)),
-		             nm_ip4_address_get_prefix (addr));
-
-		/* DNS servers */
-		for (i = 1; i < ret_array->n_values; i++) {
-			GValue *value = g_value_array_get_nth (ret_array, i);
-			guint32 tmp = g_value_get_uint (value);
-
-			if (tmp > 0) {
-				nm_ip4_config_add_nameserver (config, tmp);
-				nm_log_info (LOGD_MB, "  DNS %s", ip_address_to_string (tmp));
-			}
-		}
-		g_value_array_free (ret_array);
-	}
-
-	g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, NULL, config, error);
-	g_clear_error (&error);
-}
-
-static NMActStageReturn
-static_stage3_ip4_config_start (NMModem *self,
-                                NMActRequest *req,
-                                NMDeviceStateReason *reason)
-{
-	NMModemPrivate *priv;
-
-	g_return_val_if_fail (self != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (reason !=	NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	priv = NM_MODEM_GET_PRIVATE (self);
-
-	priv->call = dbus_g_proxy_begin_call (nm_modem_get_proxy (self, MM_DBUS_INTERFACE_MODEM),
-	                                      "GetIP4Config", static_stage3_done,
-	                                      self, NULL,
-	                                      G_TYPE_INVALID);
-
-	return NM_ACT_STAGE_RETURN_POSTPONE;
-}
-
-/*****************************************************************************/
 
 NMActStageReturn
 nm_modem_stage3_ip4_config_start (NMModem *self,
@@ -405,7 +297,7 @@ nm_modem_stage3_ip4_config_start (NMModem *self,
 		ret = ppp_stage3_ip4_config_start (self, req, reason);
 		break;
 	case MM_MODEM_IP_METHOD_STATIC:
-		ret = static_stage3_ip4_config_start (self, req, reason);
+		ret = NM_MODEM_GET_CLASS (self)->static_stage3_ip4_config_start (self, req, reason);
 		break;
 	case MM_MODEM_IP_METHOD_DHCP:
 		ret = device_class->act_stage3_ip4_config_start (device, NULL, reason);
@@ -419,6 +311,29 @@ nm_modem_stage3_ip4_config_start (NMModem *self,
 	return ret;
 }
 
+void
+nm_modem_ip4_pre_commit (NMModem *modem,
+                         NMDevice *device,
+                         NMIP4Config *config)
+{
+	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (modem);
+
+	/* If the modem has an ethernet-type data interface (ie, not PPP and thus
+	 * not point-to-point) and IP config has a /32 prefix, then we assume that
+	 * ARP will be pointless and we turn it off.
+	 */
+	if (   priv->ip_method == MM_MODEM_IP_METHOD_STATIC
+	    || priv->ip_method == MM_MODEM_IP_METHOD_DHCP) {
+		NMIP4Address *addr = nm_ip4_config_get_address (config, 0);
+
+		g_assert (addr);
+		if (nm_ip4_address_get_prefix (addr) == 32)
+			nm_system_iface_set_arp (nm_device_get_ip_ifindex (device), FALSE);
+	}
+}
+
+/*****************************************************************************/
+
 NMActStageReturn
 nm_modem_stage3_ip6_config_start (NMModem *self,
                                   NMDevice *device,
@@ -430,6 +345,8 @@ nm_modem_stage3_ip6_config_start (NMModem *self,
 	return NM_ACT_STAGE_RETURN_POSTPONE;
 }
 
+/*****************************************************************************/
+
 static void
 cancel_get_secrets (NMModem *self)
 {
@@ -486,12 +403,14 @@ nm_modem_get_secrets (NMModem *self,
 	return !!(priv->secrets_id);
 }
 
+/*****************************************************************************/
+
 static NMActStageReturn
-real_act_stage1_prepare (NMModem *modem,
-                         NMActRequest *req,
-                         GPtrArray **out_hints,
-                         const char **out_setting_name,
-                         NMDeviceStateReason *reason)
+act_stage1_prepare (NMModem *modem,
+                    NMActRequest *req,
+                    GPtrArray **out_hints,
+                    const char **out_setting_name,
+                    NMDeviceStateReason *reason)
 {
 	*reason = NM_DEVICE_STATE_REASON_UNKNOWN;
 	return NM_ACT_STAGE_RETURN_FAILURE;
@@ -541,6 +460,8 @@ nm_modem_act_stage1_prepare (NMModem *self,
 	return ret;
 }
 
+/*****************************************************************************/
+
 NMActStageReturn
 nm_modem_act_stage2_config (NMModem *self,
                             NMActRequest *req,
@@ -556,6 +477,8 @@ nm_modem_act_stage2_config (NMModem *self,
 	return NM_ACT_STAGE_RETURN_SUCCESS;
 }
 
+/*****************************************************************************/
+
 NMConnection *
 nm_modem_get_best_auto_connection (NMModem *self,
                                    GSList *connections,
@@ -566,6 +489,8 @@ nm_modem_get_best_auto_connection (NMModem *self,
 	return NULL;
 }
 
+/*****************************************************************************/
+
 gboolean
 nm_modem_check_connection_compatible (NMModem *self,
                                       NMConnection *connection,
@@ -576,6 +501,8 @@ nm_modem_check_connection_compatible (NMModem *self,
 	return FALSE;
 }
 
+/*****************************************************************************/
+
 gboolean
 nm_modem_complete_connection (NMModem *self,
                               NMConnection *connection,
@@ -587,8 +514,10 @@ nm_modem_complete_connection (NMModem *self,
 	return FALSE;
 }
 
+/*****************************************************************************/
+
 static void
-real_deactivate (NMModem *self, NMDevice *device)
+deactivate (NMModem *self, NMDevice *device)
 {
 	NMModemPrivate *priv;
 	int ifindex;
@@ -608,11 +537,6 @@ real_deactivate (NMModem *self, NMDevice *device)
 		priv->act_request = NULL;
 	}
 
-	if (priv->call) {
-		dbus_g_proxy_cancel_call (priv->proxy, priv->call);
-		priv->call = NULL;
-	}
-
 	priv->in_bytes = priv->out_bytes = 0;
 
 	if (priv->ppp_manager) {
@@ -639,24 +563,15 @@ real_deactivate (NMModem *self, NMDevice *device)
 	}
 }
 
+/*****************************************************************************/
+
 void
 nm_modem_deactivate (NMModem *self, NMDevice *device)
 {
 	NM_MODEM_GET_CLASS (self)->deactivate (self, device);
 }
 
-static void
-disconnect_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
-{
-	GError *error = NULL;
-	gboolean warn = GPOINTER_TO_UINT (user_data);
-
-	if (!dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID) && warn) {
-		nm_log_info (LOGD_MB, "disconnect failed: (%d) %s",
-		             error ? error->code : -1,
-		             error && error->message ? error->message : "(unknown)");
-	}
-}
+/*****************************************************************************/
 
 void
 nm_modem_device_state_changed (NMModem *self,
@@ -697,12 +612,7 @@ nm_modem_device_state_changed (NMModem *self,
 			/* Don't bother warning on FAILED since the modem is already gone */
 			if (new_state == NM_DEVICE_STATE_FAILED)
 				warn = FALSE;
-			dbus_g_proxy_begin_call (nm_modem_get_proxy (self, MM_DBUS_INTERFACE_MODEM),
-			                         "Disconnect",
-			                         disconnect_done,
-			                         GUINT_TO_POINTER (warn),
-			                         NULL,
-			                         G_TYPE_INVALID);
+			NM_MODEM_GET_CLASS (self)->disconnect (self, warn);
 		}
 		break;
 	default:
@@ -710,29 +620,15 @@ nm_modem_device_state_changed (NMModem *self,
 	}
 }
 
-gboolean
-nm_modem_hw_is_up (NMModem *self, NMDevice *device)
-{
-	int ifindex = nm_device_get_ip_ifindex (device);
-
-	return ifindex > 0 ? nm_system_iface_is_up (ifindex) : TRUE;
-}
-
-gboolean
-nm_modem_hw_bring_up (NMModem *self, NMDevice *device, gboolean *no_firmware)
-{
-	int ifindex = nm_device_get_ip_ifindex (device);
-
-	return ifindex > 0 ? nm_system_iface_set_up (ifindex, TRUE, no_firmware) : TRUE;
-}
+/*****************************************************************************/
 
 const char *
-nm_modem_get_iface (NMModem *self)
+nm_modem_get_uid (NMModem *self)
 {
 	g_return_val_if_fail (self != NULL, NULL);
 	g_return_val_if_fail (NM_IS_MODEM (self), NULL);
 
-	return NM_MODEM_GET_PRIVATE (self)->iface;
+	return NM_MODEM_GET_PRIVATE (self)->uid;
 }
 
 const char *
@@ -744,109 +640,22 @@ nm_modem_get_path (NMModem *self)
 	return NM_MODEM_GET_PRIVATE (self)->path;
 }
 
-static void
-get_mm_enabled_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
-{
-	NMModem *self = NM_MODEM (user_data);
-	GError *error = NULL;
-	GValue value = { 0, };
-
-	if (!dbus_g_proxy_end_call (proxy, call_id, &error,
-	                            G_TYPE_VALUE, &value,
-	                            G_TYPE_INVALID)) {
-		nm_log_warn (LOGD_MB, "failed get modem enabled state: (%d) %s",
-		             error ? error->code : -1,
-		             error && error->message ? error->message : "(unknown)");
-		return;
-	}
-
-	if (G_VALUE_HOLDS_BOOLEAN (&value)) {
-		update_mm_enabled (self, g_value_get_boolean (&value));
-	} else
-		nm_log_warn (LOGD_MB, "failed get modem enabled state: unexpected reply type");
-
-	g_value_unset (&value);
-}
-
-static void
-query_mm_enabled (NMModem *self)
-{
-	dbus_g_proxy_begin_call (NM_MODEM_GET_PRIVATE (self)->props_proxy,
-	                         "Get", get_mm_enabled_done,
-	                         self, NULL,
-	                         G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
-	                         G_TYPE_STRING, "Enabled",
-	                         G_TYPE_INVALID);
-}
-
-static void
-set_mm_enabled_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
-{
-	GError *error = NULL;
-
-	if (!dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) {
-		nm_log_warn (LOGD_MB, "failed to enable/disable modem: (%d) %s",
-		             error ? error->code : -1,
-		             error && error->message ? error->message : "(unknown)");
-	}
-
-	/* Update enabled/disabled state again */
-	query_mm_enabled (NM_MODEM (user_data));
-}
-
-void
-nm_modem_set_mm_enabled (NMModem *self, gboolean enabled)
+const char *
+nm_modem_get_control_port (NMModem *self)
 {
-	NMModemPrivate *priv;
-
-	g_return_if_fail (self != NULL);
-	g_return_if_fail (NM_IS_MODEM (self));
-
-	priv = NM_MODEM_GET_PRIVATE (self);
-
-	/* FIXME: For now this just toggles the ModemManager enabled state.  In the
-	 * future we want to tie this into rfkill state instead so that the user can
-	 * toggle rfkill status of the WWAN modem.
-	 */
+	g_return_val_if_fail (self != NULL, NULL);
+	g_return_val_if_fail (NM_IS_MODEM (self), NULL);
 
-	if (priv->mm_enabled != enabled) {
-		DBusGProxy *proxy;
-
-		proxy = nm_modem_get_proxy (self, MM_DBUS_INTERFACE_MODEM);
-		dbus_g_proxy_begin_call (proxy,
-		                         "Enable", set_mm_enabled_done,
-		                         self, NULL,
-		                         G_TYPE_BOOLEAN, enabled,
-		                         G_TYPE_INVALID);
-		/* If we are disabling the modem, stop saying that it's enabled. */
-		if (!enabled)
-			update_mm_enabled (self, enabled);
-	}
+	return NM_MODEM_GET_PRIVATE (self)->control_port;
 }
 
-static void
-modem_properties_changed (DBusGProxy *proxy,
-                          const char *interface,
-                          GHashTable *props,
-                          gpointer user_data)
+const char *
+nm_modem_get_data_port (NMModem *self)
 {
-	NMModem *self = NM_MODEM (user_data);
-	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
-	GValue *value;
-
-	if (strcmp (interface, MM_DBUS_INTERFACE_MODEM))
-		return;
-
-	value = g_hash_table_lookup (props, "Enabled");
-	if (value && G_VALUE_HOLDS_BOOLEAN (value)) {
-		update_mm_enabled (self, g_value_get_boolean (value));
-	}
+	g_return_val_if_fail (self != NULL, NULL);
+	g_return_val_if_fail (NM_IS_MODEM (self), NULL);
 
-	value = g_hash_table_lookup (props, "IpMethod");
-	if (value && G_VALUE_HOLDS_UINT (value)) {
-		priv->ip_method = g_value_get_uint (value);
-		g_object_notify (G_OBJECT (self), NM_MODEM_IP_METHOD);
-	}
+	return NM_MODEM_GET_PRIVATE (self)->data_port;
 }
 
 /*****************************************************************************/
@@ -854,9 +663,6 @@ modem_properties_changed (DBusGProxy *proxy,
 static void
 nm_modem_init (NMModem *self)
 {
-	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
-
-	priv->dbus_mgr = nm_dbus_manager_get ();
 }
 
 static GObject*
@@ -866,23 +672,17 @@ constructor (GType type,
 {
 	GObject *object;
 	NMModemPrivate *priv;
-	DBusGConnection *bus;
 
 	object = G_OBJECT_CLASS (nm_modem_parent_class)->constructor (type,
-																  n_construct_params,
-																  construct_params);
+	                                                              n_construct_params,
+	                                                              construct_params);
 	if (!object)
 		return NULL;
 
 	priv = NM_MODEM_GET_PRIVATE (object);
 
-	if (!priv->device) {
-		nm_log_err (LOGD_HW, "modem parent device not provided");
-		goto err;
-	}
-
-	if (!priv->device) {
-		nm_log_err (LOGD_HW, "modem command interface not provided");
+	if (!priv->data_port && !priv->control_port) {
+		nm_log_err (LOGD_HW, "neither modem command nor data interface provided");
 		goto err;
 	}
 
@@ -891,30 +691,6 @@ constructor (GType type,
 		goto err;
 	}
 
-	bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
-	priv->proxy = dbus_g_proxy_new_for_name (bus,
-	                                         MM_DBUS_SERVICE,
-	                                         priv->path,
-	                                         MM_DBUS_INTERFACE_MODEM);
-
-	priv->props_proxy = dbus_g_proxy_new_for_name (bus,
-	                                               MM_DBUS_SERVICE,
-	                                               priv->path,
-	                                               DBUS_INTERFACE_PROPERTIES);
-	dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_BOXED,
-	                                   G_TYPE_NONE,
-	                                   G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT,
-	                                   G_TYPE_INVALID);
-	dbus_g_proxy_add_signal (priv->props_proxy, "MmPropertiesChanged",
-	                         G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT,
-	                         G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->props_proxy, "MmPropertiesChanged",
-	                             G_CALLBACK (modem_properties_changed),
-	                             object,
-	                             NULL);
-
-	query_mm_enabled (NM_MODEM (object));
-
 	return object;
 
  err:
@@ -924,7 +700,7 @@ constructor (GType type,
 
 static void
 get_property (GObject *object, guint prop_id,
-			  GValue *value, GParamSpec *pspec)
+              GValue *value, GParamSpec *pspec)
 {
 	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object);
 
@@ -932,11 +708,14 @@ get_property (GObject *object, guint prop_id,
 	case PROP_PATH:
 		g_value_set_string (value, priv->path);
 		break;
-	case PROP_DEVICE:
-		g_value_set_string (value, priv->device);
+	case PROP_CONTROL_PORT:
+		g_value_set_string (value, priv->control_port);
 		break;
-	case PROP_IFACE:
-		g_value_set_string (value, priv->iface);
+	case PROP_DATA_PORT:
+		g_value_set_string (value, priv->data_port);
+		break;
+	case PROP_UID:
+		g_value_set_string (value, priv->uid);
 		break;
 	case PROP_IP_METHOD:
 		g_value_set_uint (value, priv->ip_method);
@@ -947,16 +726,18 @@ get_property (GObject *object, guint prop_id,
 	case PROP_ENABLED:
 		g_value_set_boolean (value, priv->mm_enabled);
 		break;
+	case PROP_CONNECTED:
+		g_value_set_boolean (value, priv->mm_connected);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
 	}
-
 }
 
 static void
 set_property (GObject *object, guint prop_id,
-			  const GValue *value, GParamSpec *pspec)
+              const GValue *value, GParamSpec *pspec)
 {
 	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object);
 
@@ -965,22 +746,27 @@ set_property (GObject *object, guint prop_id,
 		/* Construct only */
 		priv->path = g_value_dup_string (value);
 		break;
-	case PROP_DEVICE:
-		/* Construct only */
-		priv->device = g_value_dup_string (value);
+	case PROP_CONTROL_PORT:
+		priv->control_port = g_value_dup_string (value);
+		break;
+	case PROP_DATA_PORT:
+		priv->data_port = g_value_dup_string (value);
 		break;
-	case PROP_IFACE:
+	case PROP_UID:
 		/* Construct only */
-		priv->iface = g_value_dup_string (value);
+		priv->uid = g_value_dup_string (value);
 		break;
 	case PROP_IP_METHOD:
-		/* Construct only */
 		priv->ip_method = g_value_get_uint (value);
 		break;
 	case PROP_IP_TIMEOUT:
 		priv->mm_ip_timeout = g_value_get_uint (value);
 		break;
 	case PROP_ENABLED:
+		priv->mm_enabled = g_value_get_boolean (value);
+		break;
+	case PROP_CONNECTED:
+		priv->mm_connected = g_value_get_boolean (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -989,24 +775,27 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-finalize (GObject *object)
+dispose (GObject *object)
 {
 	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object);
 
-	if (priv->act_request)
+	if (priv->act_request) {
 		g_object_unref (priv->act_request);
+		priv->act_request = NULL;
+	}
 
-	if (priv->proxy)
-		g_object_unref (priv->proxy);
-
-	if (priv->props_proxy)
-		g_object_unref (priv->props_proxy);
+	G_OBJECT_CLASS (nm_modem_parent_class)->dispose (object);
+}
 
-	g_object_unref (priv->dbus_mgr);
+static void
+finalize (GObject *object)
+{
+	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object);
 
-	g_free (priv->iface);
+	g_free (priv->uid);
 	g_free (priv->path);
-	g_free (priv->device);
+	g_free (priv->control_port);
+	g_free (priv->data_port);
 
 	G_OBJECT_CLASS (nm_modem_parent_class)->finalize (object);
 }
@@ -1022,45 +811,55 @@ nm_modem_class_init (NMModemClass *klass)
 	object_class->constructor = constructor;
 	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->dispose = dispose;
 	object_class->finalize = finalize;
 
-	klass->act_stage1_prepare = real_act_stage1_prepare;
-	klass->deactivate = real_deactivate;
+	klass->act_stage1_prepare = act_stage1_prepare;
+	klass->deactivate = deactivate;
 
 	/* Properties */
+
+	g_object_class_install_property
+		(object_class, PROP_UID,
+		 g_param_spec_string (NM_MODEM_UID,
+		                      "UID",
+		                      "Modem unique ID",
+		                      NULL,
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
 	g_object_class_install_property
 		(object_class, PROP_PATH,
 		 g_param_spec_string (NM_MODEM_PATH,
-							  "DBus path",
-							  "DBus path",
-							  NULL,
-							  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+		                      "DBus path",
+		                      "DBus path",
+		                      NULL,
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property
-		(object_class, PROP_DEVICE,
-		 g_param_spec_string (NM_MODEM_DEVICE,
-		                      "Device",
-		                      "Master modem parent device",
+		(object_class, PROP_CONTROL_PORT,
+		 g_param_spec_string (NM_MODEM_CONTROL_PORT,
+		                      "Control port",
+		                      "The port controlling the modem",
 		                      NULL,
 		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property
-		(object_class, PROP_IFACE,
-		 g_param_spec_string (NM_MODEM_IFACE,
-		                      "Interface",
-		                      "Modem command interface",
+		(object_class, PROP_DATA_PORT,
+		 g_param_spec_string (NM_MODEM_DATA_PORT,
+		                      "Data port",
+		                      "The port to connect to",
 		                      NULL,
-		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
 	g_object_class_install_property
 		(object_class, PROP_IP_METHOD,
 		 g_param_spec_uint (NM_MODEM_IP_METHOD,
-							"IP method",
-							"IP method",
-							MM_MODEM_IP_METHOD_PPP,
-							MM_MODEM_IP_METHOD_DHCP,
-							MM_MODEM_IP_METHOD_PPP,
-							G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+		                    "IP method",
+		                    "IP method",
+		                    MM_MODEM_IP_METHOD_PPP,
+		                    MM_MODEM_IP_METHOD_DHCP,
+		                    MM_MODEM_IP_METHOD_PPP,
+		                    G_PARAM_READWRITE));
 
 	g_object_class_install_property
 		(object_class, PROP_IP_TIMEOUT,
@@ -1068,7 +867,7 @@ nm_modem_class_init (NMModemClass *klass)
 		                    "IP timeout",
 		                    "IP timeout",
 		                    0, 360, 20,
-		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+		                    G_PARAM_READWRITE));
 
 	g_object_class_install_property
 		(object_class, PROP_ENABLED,
@@ -1076,62 +875,70 @@ nm_modem_class_init (NMModemClass *klass)
 		                       "Enabled",
 		                       "Enabled",
 		                       TRUE,
-		                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT));
+		                       G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_CONNECTED,
+		 g_param_spec_boolean (NM_MODEM_CONNECTED,
+		                       "Connected",
+		                       "Connected",
+		                       TRUE,
+		                       G_PARAM_READWRITE));
 
 	/* Signals */
+
 	signals[PPP_STATS] =
 		g_signal_new ("ppp-stats",
-					  G_OBJECT_CLASS_TYPE (object_class),
-					  G_SIGNAL_RUN_FIRST,
-					  G_STRUCT_OFFSET (NMModemClass, ppp_stats),
-					  NULL, NULL,
-					  _nm_marshal_VOID__UINT_UINT,
-					  G_TYPE_NONE, 2,
-					  G_TYPE_UINT, G_TYPE_UINT);
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMModemClass, ppp_stats),
+		              NULL, NULL,
+		              _nm_marshal_VOID__UINT_UINT,
+		              G_TYPE_NONE, 2,
+		              G_TYPE_UINT, G_TYPE_UINT);
 
 	signals[PPP_FAILED] =
 		g_signal_new ("ppp-failed",
-					  G_OBJECT_CLASS_TYPE (object_class),
-					  G_SIGNAL_RUN_FIRST,
-					  G_STRUCT_OFFSET (NMModemClass, ppp_failed),
-					  NULL, NULL,
-					  g_cclosure_marshal_VOID__UINT,
-					  G_TYPE_NONE, 1, G_TYPE_UINT);
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMModemClass, ppp_failed),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__UINT,
+		              G_TYPE_NONE, 1, G_TYPE_UINT);
 
 	signals[IP4_CONFIG_RESULT] =
 		g_signal_new (NM_MODEM_IP4_CONFIG_RESULT,
-					  G_OBJECT_CLASS_TYPE (object_class),
-					  G_SIGNAL_RUN_FIRST,
-					  G_STRUCT_OFFSET (NMModemClass, ip4_config_result),
-					  NULL, NULL,
-					  _nm_marshal_VOID__STRING_OBJECT_POINTER,
-					  G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_OBJECT, G_TYPE_POINTER);
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMModemClass, ip4_config_result),
+		              NULL, NULL,
+		              _nm_marshal_VOID__OBJECT_POINTER,
+		              G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_POINTER);
 
 	signals[PREPARE_RESULT] =
 		g_signal_new (NM_MODEM_PREPARE_RESULT,
-					  G_OBJECT_CLASS_TYPE (object_class),
-					  G_SIGNAL_RUN_FIRST,
-					  G_STRUCT_OFFSET (NMModemClass, prepare_result),
-					  NULL, NULL,
-					  _nm_marshal_VOID__BOOLEAN_UINT,
-					  G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_UINT);
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMModemClass, prepare_result),
+		              NULL, NULL,
+		              _nm_marshal_VOID__BOOLEAN_UINT,
+		              G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_UINT);
 
 	signals[AUTH_REQUESTED] =
 		g_signal_new (NM_MODEM_AUTH_REQUESTED,
-					  G_OBJECT_CLASS_TYPE (object_class),
-					  G_SIGNAL_RUN_FIRST,
-					  G_STRUCT_OFFSET (NMModemClass, auth_requested),
-					  NULL, NULL,
-					  g_cclosure_marshal_VOID__VOID,
-					  G_TYPE_NONE, 0);
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMModemClass, auth_requested),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__VOID,
+		              G_TYPE_NONE, 0);
 
 	signals[AUTH_RESULT] =
 		g_signal_new (NM_MODEM_AUTH_RESULT,
-					  G_OBJECT_CLASS_TYPE (object_class),
-					  G_SIGNAL_RUN_FIRST,
-					  G_STRUCT_OFFSET (NMModemClass, auth_result),
-					  NULL, NULL,
-					  g_cclosure_marshal_VOID__POINTER,
-					  G_TYPE_NONE, 1, G_TYPE_POINTER);
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMModemClass, auth_result),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__POINTER,
+		              G_TYPE_NONE, 1, G_TYPE_POINTER);
 }
-
diff --git a/src/modem-manager/nm-modem.h b/src/modem-manager/nm-modem.h
index 8fe52bc0..d01aaf2c 100644
--- a/src/modem-manager/nm-modem.h
+++ b/src/modem-manager/nm-modem.h
@@ -29,19 +29,21 @@
 
 G_BEGIN_DECLS
 
-#define NM_TYPE_MODEM			(nm_modem_get_type ())
-#define NM_MODEM(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM, NMModem))
-#define NM_MODEM_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass),	NM_TYPE_MODEM, NMModemClass))
-#define NM_IS_MODEM(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM))
-#define NM_IS_MODEM_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass),	NM_TYPE_MODEM))
-#define NM_MODEM_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj),	NM_TYPE_MODEM, NMModemClass))
-
-#define NM_MODEM_PATH      "path"
-#define NM_MODEM_DEVICE    "device"
-#define NM_MODEM_IFACE     "iface"
-#define NM_MODEM_IP_METHOD "ip-method"
-#define NM_MODEM_IP_TIMEOUT "ip-timeout"
-#define NM_MODEM_ENABLED   "enabled"
+#define NM_TYPE_MODEM            (nm_modem_get_type ())
+#define NM_MODEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM, NMModem))
+#define NM_MODEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_MODEM, NMModemClass))
+#define NM_IS_MODEM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM))
+#define NM_IS_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_MODEM))
+#define NM_MODEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_MODEM, NMModemClass))
+
+#define NM_MODEM_UID          "uid"
+#define NM_MODEM_PATH         "path"
+#define NM_MODEM_CONTROL_PORT "control-port"
+#define NM_MODEM_DATA_PORT    "data-port"
+#define NM_MODEM_IP_METHOD    "ip-method"
+#define NM_MODEM_IP_TIMEOUT   "ip-timeout"
+#define NM_MODEM_ENABLED      "enabled"
+#define NM_MODEM_CONNECTED    "connected"
 
 #define NM_MODEM_PPP_STATS         "ppp-stats"
 #define NM_MODEM_PPP_FAILED        "ppp-failed"
@@ -50,6 +52,10 @@ G_BEGIN_DECLS
 #define NM_MODEM_AUTH_REQUESTED    "auth-requested"
 #define NM_MODEM_AUTH_RESULT       "auth-result"
 
+#define MM_MODEM_IP_METHOD_PPP    0
+#define MM_MODEM_IP_METHOD_STATIC 1
+#define MM_MODEM_IP_METHOD_DHCP   2
+
 typedef struct {
 	GObject parent;
 } NMModem;
@@ -83,6 +89,14 @@ typedef struct {
 	                                            const char **out_setting_name,
 	                                            NMDeviceStateReason *reason);
 
+	NMActStageReturn (*static_stage3_ip4_config_start) (NMModem *self,
+	                                                    NMActRequest *req,
+	                                                    NMDeviceStateReason *reason);
+
+	void (*set_mm_enabled)                     (NMModem *self, gboolean enabled);
+
+	void (*disconnect)                         (NMModem *self, gboolean warn);
+
 	void (*deactivate)                         (NMModem *self, NMDevice *device);
 
 	/* Signals */
@@ -90,7 +104,7 @@ typedef struct {
 	void (*ppp_failed) (NMModem *self, NMDeviceStateReason reason);
 
 	void (*prepare_result)    (NMModem *self, gboolean success, NMDeviceStateReason reason);
-	void (*ip4_config_result) (NMModem *self, const char *iface, NMIP4Config *config, GError *error);
+	void (*ip4_config_result) (NMModem *self, NMIP4Config *config, GError *error);
 
 	void (*auth_requested)    (NMModem *self);
 	void (*auth_result)       (NMModem *self, GError *error);
@@ -98,11 +112,10 @@ typedef struct {
 
 GType nm_modem_get_type (void);
 
-/* Protected */
-
-DBusGProxy *  nm_modem_get_proxy       (NMModem *modem, const char *interface);
-const char *  nm_modem_get_iface       (NMModem *modem);
-const char *  nm_modem_get_path        (NMModem *modem);
+const char *nm_modem_get_path         (NMModem *modem);
+const char *nm_modem_get_uid          (NMModem *modem);
+const char *nm_modem_get_control_port (NMModem *modem);
+const char *nm_modem_get_data_port    (NMModem *modem);
 
 NMConnection *nm_modem_get_best_auto_connection (NMModem *self,
                                                  GSList *connections,
@@ -135,6 +148,8 @@ NMActStageReturn nm_modem_stage3_ip6_config_start (NMModem *modem,
                                                    NMDeviceClass *device_class,
                                                    NMDeviceStateReason *reason);
 
+void nm_modem_ip4_pre_commit (NMModem *modem, NMDevice *device, NMIP4Config *config);
+
 gboolean nm_modem_get_secrets (NMModem *modem,
                                const char *setting_name,
                                gboolean request_new,
@@ -147,14 +162,12 @@ void nm_modem_device_state_changed (NMModem *modem,
                                     NMDeviceState old_state,
                                     NMDeviceStateReason reason);
 
-gboolean nm_modem_hw_is_up (NMModem *modem, NMDevice *device);
-
-gboolean nm_modem_hw_bring_up (NMModem *modem, NMDevice *device, gboolean *no_firmware);
-
 gboolean      nm_modem_get_mm_enabled (NMModem *self);
 
 void          nm_modem_set_mm_enabled (NMModem *self, gboolean enabled);
 
+gboolean      nm_modem_get_mm_connected (NMModem *self);
+
 G_END_DECLS
 
 #endif /* NM_MODEM_H */