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;