[PATCH] Hardening PORTCFG parse reply
Dan Williams
dcbw at redhat.com
Fri Jun 10 17:27:07 UTC 2016
On Wed, 2016-06-01 at 14:51 +0200, Carlo Lobrano wrote:
> A brief explaination of the issue that this patch solves.
> I observed a probing failure at resume from memory (S3), caused by a
> missing or wrong reply to #PORTCFG? AT command sent during port
> probing.
> This error is probably due to the overposition of multiple messages
> and replies,
> since at the same time the ModemManager is trying and close the last
> connection,
> and probing a new modem device, and the PORTCFG parser receive an
> empty string to
> parse, causing the failure.
> Therefore the fix consists in the hardening of the reply to this
> command and
> in providing a default port configuration in case of the retries are
> not enough.
Hmm, this seems like a hackish workaround... What suspend/resume
manager are you using? Ideally MM would either block suspend until it
had cleaned up and disposed the modem, or on resume it would just
force-close everything, dispose the modem, and reprobe.
Dan
> ---
>
> - Increase PORTCFG retries during initialization from 3 to 5 retries.
> - Provide a default PORTCFG configuration in case of missing or wrong
> reply.
> ---
> plugins/telit/mm-plugin-telit.c | 44 +++++++++++++++++++++++++++--
> ------------
> 1 file changed, 29 insertions(+), 15 deletions(-)
>
> diff --git a/plugins/telit/mm-plugin-telit.c b/plugins/telit/mm-
> plugin-telit.c
> index a3620e7..19eed8f 100644
> --- a/plugins/telit/mm-plugin-telit.c
> +++ b/plugins/telit/mm-plugin-telit.c
> @@ -165,8 +165,10 @@ cache_port_mode (MMDevice *device,
> r = g_regex_new ("#PORTCFG:\\s*(\\d+),(\\d+)", flags, 0, NULL);
> g_assert (r != NULL);
>
> - if (!g_regex_match_full (r, reply, strlen (reply), 0, 0,
> &match_info, &error))
> + if (!g_regex_match_full (r, reply, strlen (reply), 0, 0,
> &match_info, &error)) {
> + mm_dbg ("Unexpected PORTCFG reply '%s'. Could not parse
> it.", reply);
> goto out;
> + }
>
> if (!mm_get_uint_from_match_info (match_info, 2,
> &portcfg_current)) {
> mm_dbg ("telit: unrecognized #PORTCFG <active> value");
> @@ -201,6 +203,7 @@ cache_port_mode (MMDevice *device,
> break;
> default:
> /* portcfg value not supported */
> + mm_err ("Invalid portcfg value from reply '%s'", reply);
> goto out;
> }
> ret = TRUE;
> @@ -222,29 +225,40 @@ getportcfg_ready (MMPortSerialAt *port,
> {
> const gchar *response;
> GError *error = NULL;
> + MMDevice *device;
>
> + device = mm_port_probe_peek_device (ctx->probe);
> response = mm_port_serial_at_command_finish (port, res, &error);
> - if (error) {
> - mm_dbg ("telit: couldn't get port mode: '%s'",
> - error->message);
>
> - /* If ERROR or COMMAND NOT SUPPORT occur then do not retry
> the
> - * command.
> - */
> - if (g_error_matches (error,
> - MM_MOBILE_EQUIPMENT_ERROR,
> - MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN))
> - ctx->getportcfg_done = TRUE;
> + if (error) {
> + mm_dbg ("telit: couldn't get port mode: '%s' (retries left
> %d)",
> + error->message,
> + ctx->getportcfg_retries);
> +
> + if (ctx->getportcfg_retries == 0) {
> + mm_dbg ("telit: getportcfg last retry failed. Try and
> setting default port config.");
> + if (g_object_get_data (G_OBJECT (device),
> TAG_GETPORTCFG_SUPPORTED) == NULL) {
> + mm_dbg ("telit: Defaulting to 00 and 06 for modem
> and aux");
> + g_object_set_data (G_OBJECT (device),
> TAG_TELIT_MODEM_PORT, "00");
> + g_object_set_data (G_OBJECT (device),
> TAG_TELIT_AUX_PORT, "06");
> + g_object_set_data (G_OBJECT (device),
> TAG_GETPORTCFG_SUPPORTED, GUINT_TO_POINTER (TRUE));
> + ctx->getportcfg_done = TRUE;
> + }
> + }
> } else {
> - MMDevice *device;
> - device = mm_port_probe_peek_device (ctx->probe);
> -
> /* Results are cached in the parent device object */
> if (g_object_get_data (G_OBJECT (device),
> TAG_GETPORTCFG_SUPPORTED) == NULL) {
> mm_dbg ("telit: retrieving port mode layout");
> if (cache_port_mode (device, response)) {
> g_object_set_data (G_OBJECT (device),
> TAG_GETPORTCFG_SUPPORTED, GUINT_TO_POINTER (TRUE));
> ctx->getportcfg_done = TRUE;
> + } else {
> + mm_dbg ("telit: Error in cache port mode");
> + mm_dbg ("telit: Defaulting to 00 and 06 for modem
> and aux");
> + g_object_set_data (G_OBJECT (device),
> TAG_TELIT_MODEM_PORT, "00");
> + g_object_set_data (G_OBJECT (device),
> TAG_TELIT_AUX_PORT, "06");
> + g_object_set_data (G_OBJECT (device),
> TAG_GETPORTCFG_SUPPORTED, GUINT_TO_POINTER (TRUE));
> + ctx->getportcfg_done = TRUE;
> }
> }
>
> @@ -334,7 +348,7 @@ telit_custom_init (MMPortProbe *probe,
> ctx->port = g_object_ref (port);
> ctx->cancellable = cancellable ? g_object_ref (cancellable) :
> NULL;
> ctx->getportcfg_done = FALSE;
> - ctx->getportcfg_retries = 3;
> + ctx->getportcfg_retries = 5;
>
> /* If the device is tagged for supporting #PORTCFG do the custom
> init */
> if (g_udev_device_get_property_as_boolean (udevDevice,
> "ID_MM_TELIT_PORTS_TAGGED")) {
More information about the ModemManager-devel
mailing list