Merge remote-tracking branch 'cros/upstream' into 'cros/master'
diff --git a/AUTHORS b/AUTHORS
index 3bd9fdc..d6c2b31 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,3 +1,71 @@
-Tambet Ingo  <tambet@gmail.com>
-Dan Williams <dcbw@redhat.com>
-Aleksander Morgado <aleksander@aleksander.es>
+
+Current maintainers:
+  Dan Williams       <dcbw@redhat.com>
+  Aleksander Morgado <aleksander@aleksander.es>
+
+Previous maintainers:
+  Tambet Ingo        <tambet@gmail.com>
+
+Other contributors:
+  Ben Chan
+  Nathan Williams
+  Torgny Johansson
+  Alexander Sack
+  Guido Günther
+  Eric Shienbrood
+  Elly Jones
+  Prathmesh Prabhu
+  Thieu Le
+  Thomas Tuttle
+  Bjørn Mork
+  Marius B. Kotsbak
+  Christian Persch
+  David McCullough
+  Michael Biebl
+  Colin Walters
+  Franko Fang
+  Jason Glasgow
+  Jeroen Elebaut
+  Ori Inbar
+  David Rochberg
+  Jiří Klimeš
+  Martyn Russell
+  Graham Inggs
+  Lionel Landwerlin
+  Martin Pitt
+  Norbert Frese
+  Thomas Bechtold
+  Yegor Yefremov
+  Yunlian Jiang
+  Adrian Bunk
+  Amit Mendapara
+  Andrew Bird
+  Anton Blanchard
+  Arnd Hannemann
+  Arun Raghavan
+  Bryan Duff
+  David (Pololu)
+  David Castellanos
+  David Härdeman
+  Dmitry Ivanyushin
+  Eugene Crosser
+  Evan Nemerson
+  Fangxiaozhi (Franko)
+  Gerald Richter
+  Jens Seidel
+  Julian Oes
+  Jun Woo Lee
+  M. I. Spozta
+  Mario Blättermann
+  Michał Sroczyński
+  Nathan J. Williams
+  Noel J. Bergman
+  Quentin.Li
+  Thomas Grenman
+  Tom Bechtold
+  Tom Goetz
+  Tore Anderson
+  Vincent Untz
+  Vitaly Gimly
+  Yuri Chornoivan
+  kuonirat
diff --git a/NEWS b/NEWS
index bc3a778..e066dcb 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,47 @@
 
+ModemManager 1.4.0
+-------------------------------------------
+This is a new stable release of ModemManager.
+
+ * This version requires libmbim >= 1.10.0.
+
+This version comes with the following updates in the interfaces:
+
+ * Updated the logic around the IP configuration properties in the Bearer:
+   ** Setting DHCP as IP method in the IPv6 settings means that SLAAC should
+      be used to retrieve correct addressing and routing details.
+   ** DHCP IP method may now be combined with an explicit static IP address, as
+      IPv6 SLAAC may require the link-local address to be present.
+   ** MTU is now also included in the IP configuration properties, if specified
+      by the modem, and applicable to both DHCP and STATIC methods.
+ * New 'OFF' power state, which fully switches off the modem device. After
+   setting the modem in this state, no further use of it can be done. Currently
+   available in Wavecom and Cinterion.
+ * Location interface: new 'unmanaged GPS' support, which allows to start/stop
+   the GPS module in the modem, while leaving the location information retrieval
+   to other processes. Currently available in modems with independent GPS TTYs,
+   like Option/HSO, Cinterion and Huawei.
+ * New Test DBus interface: not to be installed, just for internal system tests.
+
+Other notable changes include:
+ * MBIM: support for ZTE and Sequans Communications modems.
+ * Ericsson MBM: Support for AT-capable /dev/cdc-wdm ports.
+ * Huawei: improved support for Network time retrieval.
+ * Huawei: implemented GPS support.
+ * Huawei: support for /dev/cdc-wdm AT ports via the new huawei-cdc-ncm driver.
+ * Cinterion: implemented GPS support.
+ * Cinterion: implemented unlock retries loading.
+ * Cinterion: gather port types for multi-tty devices.
+ * Cinterion: custom wait for SIM readiness after SIM-PIN unlock.
+ * Wavecom: custom wait for SIM readiness after SIM-PIN unlock.
+ * Probing: new flag to identify hotplugged devices which don't need full reset.
+ * Tests: internal refactor of the ports handling code, allowing test-driven
+   virtual ports and system tests run during 'make check'. This new feature also
+   comes with a new internal 'Test' DBus interface, as well as new --test-[*]
+   options in the ModemManager program.
+ * and many more fixes...
+
+
 ModemManager 1.2.0
 -------------------------------------------
 This is a new stable release of ModemManager.
diff --git a/configure.ac b/configure.ac
index bba9de5..da7fd16 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
 
 dnl The MM version number
 m4_define([mm_major_version], [1])
-m4_define([mm_minor_version], [3])
+m4_define([mm_minor_version], [5])
 m4_define([mm_micro_version], [0])
 m4_define([mm_version],
           [mm_major_version.mm_minor_version.mm_micro_version])
@@ -15,9 +15,9 @@
 dnl            with old code), increment a.
 dnl        If the interface has changed in an incompatible way (that is,
 dnl            functions have changed or been removed), then zero a.
-m4_define([mm_glib_lt_current],  [1])
+m4_define([mm_glib_lt_current],  [2])
 m4_define([mm_glib_lt_revision], [0])
-m4_define([mm_glib_lt_age],      [1])
+m4_define([mm_glib_lt_age],      [2])
 
 
 AC_INIT([ModemManager],[mm_version],[modemmanager-devel@lists.freedesktop.org],[ModemManager])
@@ -201,7 +201,7 @@
 AM_CONDITIONAL(WITH_MBIM, test "x$with_mbim" = "xyes")
 case $with_mbim in
     yes)
-        PKG_CHECK_MODULES(MBIM, [mbim-glib >= 1.9], [have_mbim=yes],[have_mbim=no])
+        PKG_CHECK_MODULES(MBIM, [mbim-glib >= 1.10], [have_mbim=yes],[have_mbim=no])
         if test "x$have_mbim" = "xno"; then
             AC_MSG_ERROR([Couldn't find libmbim-glib. Install it, or otherwise configure using --without-mbim to disable MBIM support.])
         else
diff --git a/docs/reference/api/Makefile.am b/docs/reference/api/Makefile.am
index 6079687..68029cf 100644
--- a/docs/reference/api/Makefile.am
+++ b/docs/reference/api/Makefile.am
@@ -34,7 +34,7 @@
 
 # CFLAGS and LDFLAGS for compiling scan program. Only needed
 # if $(DOC_MODULE).types is non-empty.
-INCLUDES = \
+AM_CPPFLAGS = \
 	-I$(srcdir) \
 	-I$(top_srcdir) \
 	-I$(top_builddir) \
diff --git a/docs/reference/libmm-glib/Makefile.am b/docs/reference/libmm-glib/Makefile.am
index ad0f151..e2abdbf 100644
--- a/docs/reference/libmm-glib/Makefile.am
+++ b/docs/reference/libmm-glib/Makefile.am
@@ -33,7 +33,7 @@
 
 # CFLAGS and LDFLAGS for compiling scan program. Only needed
 # if $(DOC_MODULE).types is non-empty.
-INCLUDES = \
+AM_CPPFLAGS = \
 	-I$(srcdir) \
 	-I$(top_srcdir) \
 	-I$(top_builddir) \
diff --git a/libmm-glib/mm-common-helpers.c b/libmm-glib/mm-common-helpers.c
index a8927fb..fbaa81d 100644
--- a/libmm-glib/mm-common-helpers.c
+++ b/libmm-glib/mm-common-helpers.c
@@ -1254,7 +1254,7 @@
         return FALSE;
 
     for (num = 0; str[num]; num++) {
-        if (str[num] != '-' && !g_ascii_isdigit (str[num]))
+        if (str[num] != '+' && str[num] != '-' && !g_ascii_isdigit (str[num]))
             return FALSE;
     }
 
diff --git a/plugins/huawei/mm-broadband-modem-huawei.c b/plugins/huawei/mm-broadband-modem-huawei.c
index 9cbbfb8..ce1fb6f 100644
--- a/plugins/huawei/mm-broadband-modem-huawei.c
+++ b/plugins/huawei/mm-broadband-modem-huawei.c
@@ -108,6 +108,8 @@
     FeatureSupport syscfg_support;
     FeatureSupport syscfgex_support;
     FeatureSupport prefmode_support;
+    FeatureSupport time_support;
+    FeatureSupport nwtime_support;
 
     MMModemLocationSource enabled_sources;
 
@@ -632,6 +634,8 @@
                          MM_CORE_ERROR_FAILED,
                          "Could not parse ^CPIN results: Response didn't match (%s)",
                          result);
+
+        g_match_info_free (match_info);
         g_regex_unref (r);
         return NULL;
     }
@@ -2840,70 +2844,70 @@
 /*****************************************************************************/
 /* Load network time (Time interface) */
 
-static gchar *
-modem_time_load_network_time_finish (MMIfaceModemTime *self,
-                                     GAsyncResult *res,
-                                     GError **error)
+static MMNetworkTimezone *
+modem_time_load_network_timezone_finish (MMIfaceModemTime *_self,
+                                         GAsyncResult *res,
+                                         GError **error)
 {
+    MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (_self);
+    MMNetworkTimezone *tz = NULL;
     const gchar *response;
-    GRegex *r;
-    GMatchInfo *match_info = NULL;
-    GError *match_error = NULL;
-    guint year, month, day, hour, minute, second;
-    gchar *result = NULL;
 
-    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
+    g_assert (self->priv->nwtime_support == FEATURE_SUPPORTED ||
+              self->priv->time_support == FEATURE_SUPPORTED);
+
+    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (_self), res, error);
     if (!response)
         return NULL;
 
-    /* Already in ISO-8601 format, but verify just to be sure */
-    r = g_regex_new ("\\^TIME:\\s*(\\d+)/(\\d+)/(\\d+)\\s*(\\d+):(\\d+):(\\d*)$", 0, 0, NULL);
-    g_assert (r != NULL);
+    if (self->priv->nwtime_support == FEATURE_SUPPORTED)
+        mm_huawei_parse_nwtime_response (response, NULL, &tz, error);
+    else if (self->priv->time_support == FEATURE_SUPPORTED)
+        mm_huawei_parse_time_response (response, NULL, &tz, error);
+    return tz;
+}
 
-    if (!g_regex_match_full (r, response, -1, 0, 0, &match_info, &match_error)) {
-        if (match_error) {
-            g_propagate_error (error, match_error);
-            g_prefix_error (error, "Could not parse ^TIME results: ");
-        } else {
-            g_set_error_literal (error,
-                                 MM_CORE_ERROR,
-                                 MM_CORE_ERROR_FAILED,
-                                 "Couldn't match ^TIME reply");
-        }
-    } else {
-        /* Remember that g_match_info_get_match_count() includes match #0 */
-        g_assert (g_match_info_get_match_count (match_info) >= 7);
 
-        if (mm_get_uint_from_match_info (match_info, 1, &year) &&
-            mm_get_uint_from_match_info (match_info, 2, &month) &&
-            mm_get_uint_from_match_info (match_info, 3, &day) &&
-            mm_get_uint_from_match_info (match_info, 4, &hour) &&
-            mm_get_uint_from_match_info (match_info, 5, &minute) &&
-            mm_get_uint_from_match_info (match_info, 6, &second)) {
-            /* Return ISO-8601 format date/time string */
-            result = g_strdup_printf ("%04d/%02d/%02d %02d:%02d:%02d",
-                                      year, month, day, hour, minute, second);
-        } else {
-            g_set_error_literal (error,
-                                 MM_CORE_ERROR,
-                                 MM_CORE_ERROR_FAILED,
-                                 "Failed to parse ^TIME reply");
-        }
-    }
+static gchar *
+modem_time_load_network_time_finish (MMIfaceModemTime *_self,
+                                     GAsyncResult *res,
+                                     GError **error)
+{
+    MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (_self);
+    const gchar *response;
+    gchar *iso8601 = NULL;
 
-    if (match_info)
-        g_match_info_free (match_info);
-    g_regex_unref (r);
-    return result;
+    g_assert (self->priv->nwtime_support == FEATURE_SUPPORTED ||
+              self->priv->time_support == FEATURE_SUPPORTED);
+
+    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (_self), res, error);
+    if (!response)
+        return NULL;
+
+    if (self->priv->nwtime_support == FEATURE_SUPPORTED)
+        mm_huawei_parse_nwtime_response (response, &iso8601, NULL, error);
+    else if (self->priv->time_support == FEATURE_SUPPORTED)
+        mm_huawei_parse_time_response (response, &iso8601, NULL, error);
+    return iso8601;
 }
 
 static void
-modem_time_load_network_time (MMIfaceModemTime *self,
+modem_time_load_network_time_or_zone (MMIfaceModemTime *_self,
                               GAsyncReadyCallback callback,
                               gpointer user_data)
 {
+    const char *command = NULL;
+    MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (_self);
+
+    if (self->priv->nwtime_support == FEATURE_SUPPORTED)
+        command = "^NWTIME?";
+    else if (self->priv->time_support == FEATURE_SUPPORTED)
+        command = "^TIME";
+
+    g_assert (command != NULL);
+
     mm_base_modem_at_command (MM_BASE_MODEM (self),
-                              "^TIME",
+                              command,
                               3,
                               FALSE,
                               callback,
@@ -3487,28 +3491,63 @@
 /* Check support (Time interface) */
 
 static gboolean
-modem_time_check_support_finish (MMIfaceModemTime *self,
+modem_time_check_support_finish (MMIfaceModemTime *_self,
                                  GAsyncResult *res,
                                  GError **error)
 {
-    return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+    MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (_self);
+
+    if (self->priv->nwtime_support == FEATURE_SUPPORTED)
+        return TRUE;
+    if (self->priv->time_support == FEATURE_SUPPORTED)
+        return TRUE;
+    return FALSE;
 }
 
 static void
-modem_time_check_ready (MMBroadbandModem *self,
+modem_time_check_ready (MMBaseModem *self,
                         GAsyncResult *res,
                         GSimpleAsyncResult *simple)
 {
-    GError *error = NULL;
-
-    mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
-    if (error)
-        g_simple_async_result_take_error (simple, error);
-
+    /* Responses are checked in the sequence parser, ignore overall result */
+    mm_base_modem_at_sequence_finish (self, res, NULL, NULL);
     g_simple_async_result_complete (simple);
     g_object_unref (simple);
 }
 
+static gboolean
+modem_check_time_reply (MMBaseModem *_self,
+                        gpointer none,
+                        const gchar *command,
+                        const gchar *response,
+                        gboolean last_command,
+                        const GError *error,
+                        GVariant **result,
+                        GError **result_error)
+{
+    MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (_self);
+
+    if (!error) {
+        if (strstr (response, "^NTCT"))
+            self->priv->nwtime_support = FEATURE_SUPPORTED;
+        else if (strstr (response, "^TIME"))
+            self->priv->time_support = FEATURE_SUPPORTED;
+    } else {
+        if (strstr (command, "^NTCT"))
+            self->priv->nwtime_support = FEATURE_NOT_SUPPORTED;
+        else if (strstr (command, "^TIME"))
+            self->priv->time_support = FEATURE_NOT_SUPPORTED;
+    }
+
+    return FALSE;
+}
+
+static const MMBaseModemAtCommand time_cmd_sequence[] = {
+    { "^NTCT?", 3, FALSE, modem_check_time_reply }, /* 3GPP/LTE */
+    { "^TIME",  3, FALSE, modem_check_time_reply }, /* CDMA */
+    { NULL }
+};
+
 static void
 modem_time_check_support (MMIfaceModemTime *self,
                           GAsyncReadyCallback callback,
@@ -3521,13 +3560,12 @@
                                         user_data,
                                         modem_time_check_support);
 
-    /* Only CDMA devices support this at the moment */
-    mm_base_modem_at_command (MM_BASE_MODEM (self),
-                              "^TIME",
-                              3,
-                              TRUE,
-                              (GAsyncReadyCallback)modem_time_check_ready,
-                              result);
+    mm_base_modem_at_sequence (MM_BASE_MODEM (self),
+                               time_cmd_sequence,
+                               NULL, /* response_processor_context */
+                               NULL, /* response_processor_context_free */
+                               (GAsyncReadyCallback)modem_time_check_ready,
+                               result);
 }
 
 /*****************************************************************************/
@@ -3714,6 +3752,8 @@
     self->priv->syscfg_support = FEATURE_SUPPORT_UNKNOWN;
     self->priv->syscfgex_support = FEATURE_SUPPORT_UNKNOWN;
     self->priv->prefmode_support = FEATURE_SUPPORT_UNKNOWN;
+    self->priv->nwtime_support = FEATURE_SUPPORT_UNKNOWN;
+    self->priv->time_support = FEATURE_SUPPORT_UNKNOWN;
 }
 
 static void
@@ -3845,8 +3885,10 @@
 {
     iface->check_support = modem_time_check_support;
     iface->check_support_finish = modem_time_check_support_finish;
-    iface->load_network_time = modem_time_load_network_time;
+    iface->load_network_time = modem_time_load_network_time_or_zone;
     iface->load_network_time_finish = modem_time_load_network_time_finish;
+    iface->load_network_timezone = modem_time_load_network_time_or_zone;
+    iface->load_network_timezone_finish = modem_time_load_network_timezone_finish;
 }
 
 static void
diff --git a/plugins/huawei/mm-modem-helpers-huawei.c b/plugins/huawei/mm-modem-helpers-huawei.c
index 656c6de..7612e64 100644
--- a/plugins/huawei/mm-modem-helpers-huawei.c
+++ b/plugins/huawei/mm-modem-helpers-huawei.c
@@ -1033,3 +1033,154 @@
     g_strfreev (split);
     return NULL;
 }
+
+/*****************************************************************************/
+/* ^NWTIME response parser */
+
+gboolean mm_huawei_parse_nwtime_response (const gchar *response,
+                                          gchar **iso8601p,
+                                          MMNetworkTimezone **tzp,
+                                          GError **error)
+{
+    GRegex *r;
+    GMatchInfo *match_info = NULL;
+    GError *match_error = NULL;
+    guint year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, dt = 0;
+    gint tz = 0;
+    gboolean ret = FALSE;
+
+    g_assert (iso8601p || tzp); /* at least one */
+
+    r = g_regex_new ("\\^NWTIME:\\s*(\\d+)/(\\d+)/(\\d+),(\\d+):(\\d+):(\\d*)([\\-\\+\\d]+),(\\d+)$", 0, 0, NULL);
+    g_assert (r != NULL);
+
+    if (!g_regex_match_full (r, response, -1, 0, 0, &match_info, &match_error)) {
+        if (match_error) {
+            g_propagate_error (error, match_error);
+            g_prefix_error (error, "Could not parse ^NWTIME results: ");
+        } else {
+            g_set_error_literal (error,
+                                 MM_CORE_ERROR,
+                                 MM_CORE_ERROR_FAILED,
+                                 "Couldn't match ^NWTIME reply");
+        }
+    } else {
+        /* Remember that g_match_info_get_match_count() includes match #0 */
+        g_assert (g_match_info_get_match_count (match_info) >= 9);
+
+        if (mm_get_uint_from_match_info (match_info, 1, &year) &&
+            mm_get_uint_from_match_info (match_info, 2, &month) &&
+            mm_get_uint_from_match_info (match_info, 3, &day) &&
+            mm_get_uint_from_match_info (match_info, 4, &hour) &&
+            mm_get_uint_from_match_info (match_info, 5, &minute) &&
+            mm_get_uint_from_match_info (match_info, 6, &second) &&
+            mm_get_int_from_match_info  (match_info, 7, &tz) &&
+            mm_get_uint_from_match_info (match_info, 8, &dt)) {
+            /* adjust year */
+            if (year < 100)
+                year += 2000;
+            /*
+             * tz = timezone offset in 15 minute intervals
+             * dt = daylight adjustment, 0 = none, 1 = 1 hour, 2 = 2 hours
+             *      other values are marked reserved.
+             */
+            if (iso8601p) {
+                /* Return ISO-8601 format date/time string */
+                *iso8601p = mm_new_iso8601_time (year, month, day, hour,
+                                                 minute, second,
+                                                 TRUE, (tz * 15) + (dt * 60));
+            }
+            if (tzp) {
+                *tzp = mm_network_timezone_new ();
+                mm_network_timezone_set_offset (*tzp, tz * 15);
+                mm_network_timezone_set_dst_offset (*tzp, dt * 60);
+            }
+
+            ret = TRUE;
+        } else {
+            g_set_error_literal (error,
+                                 MM_CORE_ERROR,
+                                 MM_CORE_ERROR_FAILED,
+                                 "Failed to parse ^NWTIME reply");
+        }
+    }
+
+    if (match_info)
+        g_match_info_free (match_info);
+    g_regex_unref (r);
+
+    return ret;
+}
+
+/*****************************************************************************/
+/* ^TIME response parser */
+
+gboolean mm_huawei_parse_time_response (const gchar *response,
+                                        gchar **iso8601p,
+                                        MMNetworkTimezone **tzp,
+                                        GError **error)
+{
+    GRegex *r;
+    GMatchInfo *match_info = NULL;
+    GError *match_error = NULL;
+    guint year, month, day, hour, minute, second;
+    gboolean ret = FALSE;
+
+    g_assert (iso8601p || tzp); /* at least one */
+
+    /* TIME response cannot ever provide TZ info */
+    if (tzp) {
+        g_set_error_literal (error,
+                             MM_CORE_ERROR,
+                             MM_CORE_ERROR_UNSUPPORTED,
+                             "^TIME does not provide timezone information");
+        return FALSE;
+    }
+
+    /* Already in ISO-8601 format, but verify just to be sure */
+    r = g_regex_new ("\\^TIME:\\s*(\\d+)/(\\d+)/(\\d+)\\s*(\\d+):(\\d+):(\\d*)$", 0, 0, NULL);
+    g_assert (r != NULL);
+
+    if (!g_regex_match_full (r, response, -1, 0, 0, &match_info, &match_error)) {
+        if (match_error) {
+            g_propagate_error (error, match_error);
+            g_prefix_error (error, "Could not parse ^TIME results: ");
+        } else {
+            g_set_error_literal (error,
+                                 MM_CORE_ERROR,
+                                 MM_CORE_ERROR_FAILED,
+                                 "Couldn't match ^TIME reply");
+        }
+    } else {
+        /* Remember that g_match_info_get_match_count() includes match #0 */
+        g_assert (g_match_info_get_match_count (match_info) >= 7);
+
+        if (mm_get_uint_from_match_info (match_info, 1, &year) &&
+            mm_get_uint_from_match_info (match_info, 2, &month) &&
+            mm_get_uint_from_match_info (match_info, 3, &day) &&
+            mm_get_uint_from_match_info (match_info, 4, &hour) &&
+            mm_get_uint_from_match_info (match_info, 5, &minute) &&
+            mm_get_uint_from_match_info (match_info, 6, &second)) {
+            /* adjust year */
+            if (year < 100)
+                year += 2000;
+            /* Return ISO-8601 format date/time string */
+            if (iso8601p)
+                *iso8601p = mm_new_iso8601_time (year, month, day, hour,
+                                                 minute, second, FALSE, 0);
+            ret = TRUE;
+        } else {
+            g_set_error_literal (error,
+                                 MM_CORE_ERROR,
+                                 MM_CORE_ERROR_FAILED,
+                                 "Failed to parse ^TIME reply");
+        }
+    }
+
+    if (match_info)
+        g_match_info_free (match_info);
+    g_regex_unref (r);
+
+    return ret;
+}
+
diff --git a/plugins/huawei/mm-modem-helpers-huawei.h b/plugins/huawei/mm-modem-helpers-huawei.h
index 05894f3..e225e90 100644
--- a/plugins/huawei/mm-modem-helpers-huawei.h
+++ b/plugins/huawei/mm-modem-helpers-huawei.h
@@ -113,4 +113,20 @@
                                                                       const GArray *supported_mode_combinations,
                                                                       GError **error);
 
+/*****************************************************************************/
+/* ^NWTIME response parser */
+
+gboolean mm_huawei_parse_nwtime_response (const gchar *response,
+                                          gchar **iso8601p,
+                                          MMNetworkTimezone **tzp,
+                                          GError **error);
+
+/*****************************************************************************/
+/* ^TIME response parser */
+
+gboolean mm_huawei_parse_time_response (const gchar *response,
+                                        gchar **iso8601p,
+                                        MMNetworkTimezone **tzp,
+                                        GError **error);
+
 #endif  /* MM_MODEM_HELPERS_HUAWEI_H */
diff --git a/plugins/huawei/tests/test-modem-helpers-huawei.c b/plugins/huawei/tests/test-modem-helpers-huawei.c
index b74821f..9e92eee 100644
--- a/plugins/huawei/tests/test-modem-helpers-huawei.c
+++ b/plugins/huawei/tests/test-modem-helpers-huawei.c
@@ -1002,6 +1002,138 @@
 }
 
 /*****************************************************************************/
+/* Test ^NWTIME responses */
+
+typedef struct {
+    const gchar *str;
+    gboolean ret;
+    gboolean test_iso8601;
+    gboolean test_tz;
+    gchar *iso8601;
+    gint32 offset;
+    gint32 dst_offset;
+    gint32 leap_seconds;
+} NwtimeTest;
+
+#define NWT_UNKNOWN    MM_NETWORK_TIMEZONE_LEAP_SECONDS_UNKNOWN
+
+static const NwtimeTest nwtime_tests[] = {
+    { "^NWTIME: 14/08/05,04:00:21+40,00", TRUE, TRUE, FALSE,
+        "2014-08-05T04:00:21+10:00", 600, 0, NWT_UNKNOWN },
+    { "^NWTIME: 14/08/05,04:00:21+40,00", TRUE, FALSE, TRUE,
+        "2014-08-05T04:00:21+10:00", 600, 0, NWT_UNKNOWN },
+    { "^NWTIME: 14/08/05,04:00:21+40,00", TRUE, TRUE, TRUE,
+        "2014-08-05T04:00:21+10:00", 600, 0, NWT_UNKNOWN },
+
+    { "^NWTIME: 14/08/05,04:00:21+20,00", TRUE, TRUE, FALSE,
+        "2014-08-05T04:00:21+05:00", 300, 0, NWT_UNKNOWN },
+    { "^NWTIME: 14/08/05,04:00:21+20,00", TRUE, FALSE, TRUE,
+        "2014-08-05T04:00:21+05:00", 300, 0, NWT_UNKNOWN },
+    { "^NWTIME: 14/08/05,04:00:21+20,00", TRUE, TRUE, TRUE,
+        "2014-08-05T04:00:21+05:00", 300, 0, NWT_UNKNOWN },
+
+    { "^NWTIME: 14/08/05,04:00:21+40,01", TRUE, TRUE, FALSE,
+        "2014-08-05T04:00:21+11:00", 600, 60, NWT_UNKNOWN },
+    { "^NWTIME: 14/08/05,04:00:21+40,01", TRUE, FALSE, TRUE,
+        "2014-08-05T04:00:21+11:00", 600, 60, NWT_UNKNOWN },
+    { "^NWTIME: 14/08/05,04:00:21+40,01", TRUE, TRUE, TRUE,
+        "2014-08-05T04:00:21+11:00", 600, 60, NWT_UNKNOWN },
+
+    { "^NWTIME: 14/08/05,04:00:21+40,02", TRUE, TRUE, FALSE,
+        "2014-08-05T04:00:21+12:00", 600, 120, NWT_UNKNOWN },
+    { "^NWTIME: 14/08/05,04:00:21+40,02", TRUE, FALSE, TRUE,
+        "2014-08-05T04:00:21+12:00", 600, 120, NWT_UNKNOWN },
+    { "^NWTIME: 14/08/05,04:00:21+40,02", TRUE, TRUE, TRUE,
+        "2014-08-05T04:00:21+12:00", 600, 120, NWT_UNKNOWN },
+
+    { "^TIME: XX/XX/XX,XX:XX:XX+XX,XX", FALSE, TRUE, FALSE,
+        NULL, NWT_UNKNOWN, NWT_UNKNOWN, NWT_UNKNOWN },
+
+    { "^TIME: 14/08/05,04:00:21+40,00", FALSE, TRUE, FALSE,
+        NULL, NWT_UNKNOWN, NWT_UNKNOWN, NWT_UNKNOWN },
+
+    { NULL, FALSE, FALSE, FALSE, NULL, NWT_UNKNOWN, NWT_UNKNOWN, NWT_UNKNOWN }
+};
+
+static void
+test_nwtime (void)
+{
+    guint i;
+
+    for (i = 0; nwtime_tests[i].str; i++) {
+        GError *error = NULL;
+        gchar *iso8601 = NULL;
+        MMNetworkTimezone *tz = NULL;
+        gboolean ret;
+
+        ret = mm_huawei_parse_nwtime_response (nwtime_tests[i].str,
+                                               nwtime_tests[i].test_iso8601 ? &iso8601 : NULL,
+                                               nwtime_tests[i].test_tz ? &tz : NULL,
+                                               &error);
+
+        g_assert (ret == nwtime_tests[i].ret);
+        g_assert (ret == (error ? FALSE : TRUE));
+
+        g_clear_error (&error);
+
+        if (nwtime_tests[i].test_iso8601)
+            g_assert_cmpstr (nwtime_tests[i].iso8601, ==, iso8601);
+
+        if (nwtime_tests[i].test_tz) {
+            g_assert (nwtime_tests[i].offset == mm_network_timezone_get_offset (tz));
+            g_assert (nwtime_tests[i].dst_offset == mm_network_timezone_get_dst_offset (tz));
+            g_assert (nwtime_tests[i].leap_seconds == mm_network_timezone_get_leap_seconds (tz));
+        }
+
+        if (iso8601)
+            g_free (iso8601);
+    }
+}
+
+/*****************************************************************************/
+/* Test ^TIME responses */
+
+typedef struct {
+    const gchar *str;
+    gboolean ret;
+    gchar *iso8601;
+} TimeTest;
+
+static const TimeTest time_tests[] = {
+    { "^TIME: 14/08/05 04:00:21", TRUE, "2014-08-05T04:00:21" },
+    { "^TIME: 2014/08/05 04:00:21", TRUE, "2014-08-05T04:00:21" },
+    { "^TIME: 14-08-05 04:00:21", FALSE, NULL },
+    { "^TIME: 14-08-05,04:00:21", FALSE, NULL },
+    { "^TIME: 14/08/05 04:00:21 AEST", FALSE, NULL },
+    { NULL, FALSE, NULL }
+};
+
+static void
+test_time (void)
+{
+    guint i;
+
+    for (i = 0; time_tests[i].str; i++) {
+        GError *error = NULL;
+        gchar *iso8601 = NULL;
+        gboolean ret;
+
+        ret = mm_huawei_parse_time_response (time_tests[i].str,
+                                             &iso8601,
+                                             NULL,
+                                             &error);
+
+        g_assert (ret == time_tests[i].ret);
+        g_assert (ret == (error ? FALSE : TRUE));
+
+        g_assert_cmpstr (time_tests[i].iso8601, ==, iso8601);
+
+        if (iso8601)
+            g_free (iso8601);
+    }
+}
+
+/*****************************************************************************/
 
 void
 _mm_log (const char *loc,
@@ -1039,6 +1171,8 @@
     g_test_add_func ("/MM/huawei/syscfg/response", test_syscfg_response);
     g_test_add_func ("/MM/huawei/syscfgex", test_syscfgex);
     g_test_add_func ("/MM/huawei/syscfgex/response", test_syscfgex_response);
+    g_test_add_func ("/MM/huawei/nwtime", test_nwtime);
+    g_test_add_func ("/MM/huawei/time", test_time);
 
     return g_test_run ();
 }
diff --git a/plugins/mtk/mm-broadband-modem-mtk.c b/plugins/mtk/mm-broadband-modem-mtk.c
index 63b37ac..df90046 100644
--- a/plugins/mtk/mm-broadband-modem-mtk.c
+++ b/plugins/mtk/mm-broadband-modem-mtk.c
@@ -218,7 +218,7 @@
             G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
     g_assert (r != NULL);
 
-    if(!g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &match_error)) {
+    if (!g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &match_error)) {
         if (match_error) {
             g_propagate_error (&error, match_error);
         } else {
@@ -228,8 +228,9 @@
                          "Failed to match EGMR response: %s", response);
         }
 
+        g_match_info_free (match_info);
         g_regex_unref (r);
-            return;
+        return;
     }
 
     if (!mm_get_int_from_match_info (match_info, 1, &device_type)) {
diff --git a/plugins/novatel/mm-broadband-modem-novatel.c b/plugins/novatel/mm-broadband-modem-novatel.c
index e4b6b6a..765595e 100644
--- a/plugins/novatel/mm-broadband-modem-novatel.c
+++ b/plugins/novatel/mm-broadband-modem-novatel.c
@@ -195,6 +195,7 @@
                                              response);
         g_simple_async_result_complete (simple);
         g_object_unref (simple);
+        g_match_info_free (match_info);
         g_regex_unref (r);
         return;
     }
diff --git a/plugins/x22x/mm-broadband-modem-x22x.c b/plugins/x22x/mm-broadband-modem-x22x.c
index 0cfccb4..ee611f2 100644
--- a/plugins/x22x/mm-broadband-modem-x22x.c
+++ b/plugins/x22x/mm-broadband-modem-x22x.c
@@ -145,6 +145,7 @@
                          "Couldn't match +SYSSEL reply: %s", response);
         }
 
+        g_match_info_free (match_info);
         g_regex_unref (r);
         return FALSE;
     }
diff --git a/src/mm-bearer-qmi.c b/src/mm-bearer-qmi.c
index c25b9f7..95ab4f7 100644
--- a/src/mm-bearer-qmi.c
+++ b/src/mm-bearer-qmi.c
@@ -33,10 +33,18 @@
 #include "mm-log.h"
 #include "mm-modem-helpers.h"
 
-G_DEFINE_TYPE (MMBearerQmi, mm_bearer_qmi, MM_TYPE_BASE_BEARER);
+G_DEFINE_TYPE (MMBearerQmi, mm_bearer_qmi, MM_TYPE_BASE_BEARER)
 
 #define GLOBAL_PACKET_DATA_HANDLE 0xFFFFFFFF
 
+enum {
+    PROP_0,
+    PROP_FORCE_DHCP,
+    PROP_LAST
+};
+
+static GParamSpec *properties[PROP_LAST];
+
 struct _MMBearerQmiPrivate {
     /* State kept while connected */
     QmiClientWds *client_ipv4;
@@ -44,6 +52,7 @@
     MMPort *data;
     guint32 packet_data_handle_ipv4;
     guint32 packet_data_handle_ipv6;
+    gboolean force_dhcp;
 };
 
 /*****************************************************************************/
@@ -261,7 +270,9 @@
 }
 
 static MMBearerIpConfig *
-get_ipv4_config (QmiMessageWdsGetCurrentSettingsOutput *output, guint32 mtu)
+get_ipv4_config (MMBearerQmi *self,
+                 QmiMessageWdsGetCurrentSettingsOutput *output,
+                 guint32 mtu)
 {
     MMBearerIpConfig *config;
     char buf[INET_ADDRSTRLEN];
@@ -291,46 +302,50 @@
     mm_dbg ("QMI IPv4 Settings:");
 
     config = mm_bearer_ip_config_new ();
-    mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_STATIC);
+    if (self->priv->force_dhcp)
+        mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_DHCP);
+    else {
+        mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_STATIC);        
 
-    /* IPv4 address */
-    qmi_inet4_ntop (addr, buf, sizeof (buf));
-    mm_bearer_ip_config_set_address (config, buf);
-    mm_bearer_ip_config_set_prefix (config, prefix);
-    mm_dbg ("    Address: %s/%d", buf, prefix);
-
-    /* IPv4 gateway address */
-    if (qmi_message_wds_get_current_settings_output_get_ipv4_gateway_address (output, &addr, &error)) {
+        /* IPv4 address */
         qmi_inet4_ntop (addr, buf, sizeof (buf));
-        mm_bearer_ip_config_set_gateway (config, buf);
-        mm_dbg ("    Gateway: %s", buf);
-    } else {
-        mm_dbg ("    Gateway: failed (%s)", error->message);
-        g_clear_error (&error);
-    }
+        mm_bearer_ip_config_set_address (config, buf);
+        mm_bearer_ip_config_set_prefix (config, prefix);
+        mm_dbg ("    Address: %s/%d", buf, prefix);
 
-    /* IPv4 DNS #1 */
-    if (qmi_message_wds_get_current_settings_output_get_primary_ipv4_dns_address (output, &addr, &error)) {
-        qmi_inet4_ntop (addr, buf, sizeof (buf));
-        dns[dns_idx++] = buf;
-        mm_dbg ("    DNS #1: %s", buf);
-    } else {
-        mm_dbg ("    DNS #1: failed (%s)", error->message);
-        g_clear_error (&error);
-    }
+        /* IPv4 gateway address */
+        if (qmi_message_wds_get_current_settings_output_get_ipv4_gateway_address (output, &addr, &error)) {
+            qmi_inet4_ntop (addr, buf, sizeof (buf));
+            mm_bearer_ip_config_set_gateway (config, buf);
+            mm_dbg ("    Gateway: %s", buf);
+        } else {
+            mm_dbg ("    Gateway: failed (%s)", error->message);
+            g_clear_error (&error);
+        }
 
-    /* IPv6 DNS #2 */
-    if (qmi_message_wds_get_current_settings_output_get_secondary_ipv4_dns_address (output, &addr, &error)) {
-        qmi_inet4_ntop (addr, buf2, sizeof (buf2));
-        dns[dns_idx++] = buf2;
-        mm_dbg ("    DNS #2: %s", buf2);
-    } else {
-        mm_dbg ("    DNS #2: failed (%s)", error->message);
-        g_clear_error (&error);
-    }
+        /* IPv4 DNS #1 */
+        if (qmi_message_wds_get_current_settings_output_get_primary_ipv4_dns_address (output, &addr, &error)) {
+            qmi_inet4_ntop (addr, buf, sizeof (buf));
+            dns[dns_idx++] = buf;
+            mm_dbg ("    DNS #1: %s", buf);
+        } else {
+            mm_dbg ("    DNS #1: failed (%s)", error->message);
+            g_clear_error (&error);
+        }
 
-    if (dns_idx > 0)
-        mm_bearer_ip_config_set_dns (config, (const gchar **) &dns);
+        /* IPv6 DNS #2 */
+        if (qmi_message_wds_get_current_settings_output_get_secondary_ipv4_dns_address (output, &addr, &error)) {
+            qmi_inet4_ntop (addr, buf2, sizeof (buf2));
+            dns[dns_idx++] = buf2;
+            mm_dbg ("    DNS #2: %s", buf2);
+        } else {
+            mm_dbg ("    DNS #2: failed (%s)", error->message);
+            g_clear_error (&error);
+        }
+
+        if (dns_idx > 0)
+            mm_bearer_ip_config_set_dns (config, (const gchar **) &dns);
+    }
 
     if (mtu) {
         mm_bearer_ip_config_set_mtu (config, mtu);
@@ -360,7 +375,9 @@
 }
 
 static MMBearerIpConfig *
-get_ipv6_config (QmiMessageWdsGetCurrentSettingsOutput *output, guint32 mtu)
+get_ipv6_config (MMBearerQmi *self,
+                 QmiMessageWdsGetCurrentSettingsOutput *output,
+                 guint32 mtu)
 {
     MMBearerIpConfig *config;
     char buf[INET6_ADDRSTRLEN];
@@ -381,7 +398,11 @@
     mm_dbg ("QMI IPv6 Settings:");
 
     config = mm_bearer_ip_config_new ();
-    mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_STATIC);
+    if (self->priv->force_dhcp)
+        /* Force DHCP, but still set the static IPv6 config details if we get them */
+        mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_DHCP);
+    else
+        mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_STATIC);
 
     /* IPv6 address */
     qmi_inet6_ntop (array, buf, sizeof (buf));
@@ -472,9 +493,9 @@
         }
 
         if (ip_family == QMI_WDS_IP_FAMILY_IPV4)
-            ctx->ipv4_config = get_ipv4_config (output, mtu);
+            ctx->ipv4_config = get_ipv4_config (ctx->self, output, mtu);
         else if (ip_family == QMI_WDS_IP_FAMILY_IPV6)
-            ctx->ipv6_config = get_ipv6_config (output, mtu);
+            ctx->ipv6_config = get_ipv6_config (ctx->self, output, mtu);
 
         /* Domain names */
         if (qmi_message_wds_get_current_settings_output_get_domain_name_list (output, &array, &error)) {
@@ -1291,7 +1312,8 @@
 
 MMBaseBearer *
 mm_bearer_qmi_new (MMBroadbandModemQmi *modem,
-                   MMBearerProperties *config)
+                   MMBearerProperties *config,
+                   gboolean force_dhcp)
 {
     MMBaseBearer *bearer;
 
@@ -1301,6 +1323,7 @@
     bearer = g_object_new (MM_TYPE_BEARER_QMI,
                            MM_BASE_BEARER_MODEM, modem,
                            MM_BASE_BEARER_CONFIG, config,
+                           MM_BEARER_QMI_FORCE_DHCP, force_dhcp,
                            NULL);
 
     /* Only export valid bearers */
@@ -1319,6 +1342,42 @@
 }
 
 static void
+set_property (GObject *object,
+              guint prop_id,
+              const GValue *value,
+              GParamSpec *pspec)
+{
+    MMBearerQmi *self = MM_BEARER_QMI (object);
+
+    switch (prop_id) {
+    case PROP_FORCE_DHCP:
+        self->priv->force_dhcp = g_value_get_boolean (value);
+        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)
+{
+    MMBearerQmi *self = MM_BEARER_QMI (object);
+
+    switch (prop_id) {
+    case PROP_FORCE_DHCP:
+        g_value_set_boolean (value, self->priv->force_dhcp);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
 dispose (GObject *object)
 {
     MMBearerQmi *self = MM_BEARER_QMI (object);
@@ -1340,10 +1399,21 @@
 
     /* Virtual methods */
     object_class->dispose = dispose;
+    object_class->get_property = get_property;
+    object_class->set_property = set_property;
 
     base_bearer_class->connect = _connect;
     base_bearer_class->connect_finish = connect_finish;
     base_bearer_class->disconnect = disconnect;
     base_bearer_class->disconnect_finish = disconnect_finish;
     base_bearer_class->report_connection_status = report_connection_status;
+
+    /* Properties */
+    properties[PROP_FORCE_DHCP] =
+        g_param_spec_boolean (MM_BEARER_QMI_FORCE_DHCP,
+                              "Force DHCP",
+                              "Never setup static IP config, always DHCP.",
+                              FALSE,
+                              G_PARAM_READWRITE);
+    g_object_class_install_property (object_class, PROP_FORCE_DHCP, properties[PROP_FORCE_DHCP]);
 }
diff --git a/src/mm-bearer-qmi.h b/src/mm-bearer-qmi.h
index b29fed3..b17f1d4 100644
--- a/src/mm-bearer-qmi.h
+++ b/src/mm-bearer-qmi.h
@@ -38,6 +38,8 @@
 typedef struct _MMBearerQmiClass MMBearerQmiClass;
 typedef struct _MMBearerQmiPrivate MMBearerQmiPrivate;
 
+#define MM_BEARER_QMI_FORCE_DHCP "bearer-qmi-force-dhcp"
+
 struct _MMBearerQmi {
     MMBaseBearer parent;
     MMBearerQmiPrivate *priv;
@@ -52,6 +54,7 @@
 /* QMI bearer creation implementation.
  * NOTE it is *not* a broadband bearer, so not async-initable */
 MMBaseBearer *mm_bearer_qmi_new (MMBroadbandModemQmi *modem,
-                                 MMBearerProperties *config);
+                                 MMBearerProperties *config,
+                                 gboolean force_dhcp);
 
 #endif /* MM_BEARER_QMI_H */
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c
index 1092ba2..277d43d 100644
--- a/src/mm-broadband-modem-qmi.c
+++ b/src/mm-broadband-modem-qmi.c
@@ -318,7 +318,7 @@
 
     /* We just create a MMBearerQmi */
     mm_dbg ("Creating QMI bearer in QMI modem");
-    bearer = mm_bearer_qmi_new (MM_BROADBAND_MODEM_QMI (self), properties);
+    bearer = mm_bearer_qmi_new (MM_BROADBAND_MODEM_QMI (self), properties, TRUE);
     g_simple_async_result_set_op_res_gpointer (result, bearer, g_object_unref);
     g_simple_async_result_complete_in_idle (result);
     g_object_unref (result);
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
index 93be6a5..17c128c 100644
--- a/src/mm-broadband-modem.c
+++ b/src/mm-broadband-modem.c
@@ -5981,6 +5981,7 @@
                                          MM_CORE_ERROR_INVALID_ARGS,
                                          "Couldn't parse SMS list response");
         list_parts_context_complete_and_free (ctx);
+        g_match_info_free (match_info);
         g_regex_unref (r);
         return;
     }
diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c
index 45e273a..7c31f9a 100644
--- a/src/mm-iface-modem.c
+++ b/src/mm-iface-modem.c
@@ -888,10 +888,10 @@
         /* Log */
         old_access_tech_string = mm_modem_access_technology_build_string_from_mask (old_access_tech);
         new_access_tech_string = mm_modem_access_technology_build_string_from_mask (built_access_tech);
-        mm_info ("Modem %s: access technology changed (%s -> %s)",
-                 g_dbus_object_get_object_path (G_DBUS_OBJECT (self)),
-                 old_access_tech_string,
-                 new_access_tech_string);
+        mm_dbg ("Modem %s: access technology changed (%s -> %s)",
+                g_dbus_object_get_object_path (G_DBUS_OBJECT (self)),
+                old_access_tech_string,
+                new_access_tech_string);
         g_free (old_access_tech_string);
         g_free (new_access_tech_string);
     }
diff --git a/src/mm-plugin.c b/src/mm-plugin.c
index 1e9512a..cbdf06d 100644
--- a/src/mm-plugin.c
+++ b/src/mm-plugin.c
@@ -632,21 +632,6 @@
     return (MMPluginSupportsResult) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)));
 }
 
-static gboolean
-find_driver_in_device (MMDevice *device,
-                       const gchar *driver)
-{
-    const gchar **device_drivers;
-    guint i;
-
-    device_drivers = mm_device_get_drivers (device);
-    for (i = 0; device_drivers[i]; i++) {
-        if (g_str_equal (driver, device_drivers[i]))
-            return TRUE;
-    }
-    return FALSE;
-}
-
 void
 mm_plugin_supports_port (MMPlugin *self,
                          MMDevice *device,
@@ -723,9 +708,9 @@
     } else {
         /* cdc-wdm ports... */
         probe_run_flags = MM_PORT_PROBE_NONE;
-        if (self->priv->qmi && find_driver_in_device (device, "qmi_wwan"))
+        if (self->priv->qmi && g_str_equal (mm_device_utils_get_port_driver (port), "qmi_wwan"))
             probe_run_flags |= MM_PORT_PROBE_QMI;
-        else if (self->priv->mbim && find_driver_in_device (device, "cdc_mbim"))
+        else if (self->priv->mbim && g_str_equal (mm_device_utils_get_port_driver (port), "cdc_mbim"))
             probe_run_flags |= MM_PORT_PROBE_MBIM;
         else
             probe_run_flags |= MM_PORT_PROBE_AT;