diff --git a/plugins/cinterion/mm-broadband-modem-cinterion.c b/plugins/cinterion/mm-broadband-modem-cinterion.c
index 4986eea5091e19dae5907179dfeee2e8c6c3de92..9b085433b3745accb7179bb20cf4973bbfaf8fd7 100644
--- a/plugins/cinterion/mm-broadband-modem-cinterion.c
+++ b/plugins/cinterion/mm-broadband-modem-cinterion.c
@@ -2154,22 +2154,59 @@ set_bands_3g (GTask  *task,
                                   FALSE,
                                   (GAsyncReadyCallback)scfg_set_ready,
                                   task);
-    } else { /* self->priv->rb_format == MM_CINTERION_RADIO_BAND_FORMAT_MULTIPLE */
+        return;
+    }
+
+    if (self->priv->rb_format == MM_CINTERION_RADIO_BAND_FORMAT_MULTIPLE) {
         if (self->priv->modem_family == MM_CINTERION_MODEM_FAMILY_IMT) {
             g_autofree gchar *bandstr2G = NULL;
             g_autofree gchar *bandstr3G = NULL;
             g_autofree gchar *bandstr4G = NULL;
+            g_autofree gchar *bandstr2G_enc = NULL;
+            g_autofree gchar *bandstr3G_enc = NULL;
+            g_autofree gchar *bandstr4G_enc = NULL;
 
             bandstr2G = g_strdup_printf ("0x%08X", band[MM_CINTERION_RB_BLOCK_GSM]);
             bandstr3G = g_strdup_printf ("0x%08X", band[MM_CINTERION_RB_BLOCK_UMTS]);
             bandstr4G = g_strdup_printf ("0x%08X", band[MM_CINTERION_RB_BLOCK_LTE_LOW]);
-            bandstr2G = mm_broadband_modem_take_and_convert_to_current_charset (MM_BROADBAND_MODEM (self), bandstr2G);
-            bandstr3G = mm_broadband_modem_take_and_convert_to_current_charset (MM_BROADBAND_MODEM (self), bandstr3G);
-            bandstr4G = mm_broadband_modem_take_and_convert_to_current_charset (MM_BROADBAND_MODEM (self), bandstr4G);
+
+            bandstr2G_enc = mm_modem_charset_str_from_utf8 (bandstr2G,
+                                                            mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (self)),
+                                                            FALSE,
+                                                            &error);
+            if (!bandstr2G_enc) {
+                g_prefix_error (&error, "Couldn't convert 2G band string to current charset: ");
+                g_task_return_error (task, error);
+                g_object_unref (task);
+                return;
+            }
+
+            bandstr3G_enc = mm_modem_charset_str_from_utf8 (bandstr3G,
+                                                            mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (self)),
+                                                            FALSE,
+                                                            &error);
+            if (!bandstr3G_enc) {
+                g_prefix_error (&error, "Couldn't convert 3G band string to current charset: ");
+                g_task_return_error (task, error);
+                g_object_unref (task);
+                return;
+            }
+
+            bandstr4G_enc = mm_modem_charset_str_from_utf8 (bandstr4G,
+                                                            mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (self)),
+                                                            FALSE,
+                                                            &error);
+            if (!bandstr4G_enc) {
+                g_prefix_error (&error, "Couldn't convert 4G band string to current charset: ");
+                g_task_return_error (task, error);
+                g_object_unref (task);
+                return;
+            }
+
             self->priv->cmds = g_new0 (MMBaseModemAtCommandAlloc, 3 + 1);
-            self->priv->cmds[0].command = g_strdup_printf ("^SCFG=\"Radio/Band/2G\",\"%s\"", bandstr2G);
-            self->priv->cmds[1].command = g_strdup_printf ("^SCFG=\"Radio/Band/3G\",\"%s\"", bandstr3G);
-            self->priv->cmds[2].command = g_strdup_printf ("^SCFG=\"Radio/Band/4G\",\"%s\"", bandstr4G);
+            self->priv->cmds[0].command = g_strdup_printf ("^SCFG=\"Radio/Band/2G\",\"%s\"", bandstr2G_enc);
+            self->priv->cmds[1].command = g_strdup_printf ("^SCFG=\"Radio/Band/3G\",\"%s\"", bandstr3G_enc);
+            self->priv->cmds[2].command = g_strdup_printf ("^SCFG=\"Radio/Band/4G\",\"%s\"", bandstr4G_enc);
             self->priv->cmds[0].timeout = self->priv->cmds[1].timeout = self->priv->cmds[2].timeout = 60;
         } else {
             self->priv->cmds = g_new0 (MMBaseModemAtCommandAlloc, 3 + 1);
@@ -2185,8 +2222,10 @@ set_bands_3g (GTask  *task,
                                    NULL,
                                    (GAsyncReadyCallback)scfg_set_ready_sequence,
                                    task);
+        return;
     }
 
+    g_assert_not_reached ();
 }
 
 static void
@@ -2196,8 +2235,9 @@ set_bands_2g (GTask  *task,
     MMBroadbandModemCinterion *self;
     GError                    *error = NULL;
     guint                      band[MM_CINTERION_RB_BLOCK_N] = { 0 };
-    gchar                     *cmd;
-    gchar                     *bandstr;
+    g_autofree gchar          *cmd = NULL;
+    g_autofree gchar          *bandstr = NULL;
+    g_autofree gchar          *bandstr_enc = NULL;
 
     self = g_task_get_source_object (task);
 
@@ -2215,12 +2255,13 @@ set_bands_2g (GTask  *task,
 
     /* Build string with the value, in the proper charset */
     bandstr = g_strdup_printf ("%u", band[MM_CINTERION_RB_BLOCK_LEGACY]);
-    bandstr = mm_broadband_modem_take_and_convert_to_current_charset (MM_BROADBAND_MODEM (self), bandstr);
-    if (!bandstr) {
-        g_task_return_new_error (task,
-                                 MM_CORE_ERROR,
-                                 MM_CORE_ERROR_UNSUPPORTED,
-                                 "Couldn't convert band set to current charset");
+    bandstr_enc = mm_modem_charset_str_from_utf8 (bandstr,
+                                                  mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (self)),
+                                                  FALSE,
+                                                  &error);
+    if (!bandstr_enc) {
+        g_prefix_error (&error, "Couldn't convert band string to current charset: ");
+        g_task_return_error (task, error);
         g_object_unref (task);
         return;
     }
@@ -2231,17 +2272,13 @@ set_bands_2g (GTask  *task,
      * the modem to connect at that specific frequency only. Note that we will be
      * passing double-quote enclosed strings here!
      */
-    cmd = g_strdup_printf ("^SCFG=\"Radio/Band\",\"%s\",\"%s\"", bandstr, bandstr);
-
+    cmd = g_strdup_printf ("^SCFG=\"Radio/Band\",\"%s\",\"%s\"", bandstr_enc, bandstr_enc);
     mm_base_modem_at_command (MM_BASE_MODEM (self),
                               cmd,
                               15,
                               FALSE,
                               (GAsyncReadyCallback)scfg_set_ready,
                               task);
-
-    g_free (cmd);
-    g_free (bandstr);
 }
 
 static void
diff --git a/plugins/mbm/mm-broadband-bearer-mbm.c b/plugins/mbm/mm-broadband-bearer-mbm.c
index b4bba2d93dcd7cee2ae2d14c3e22ea7cff1c02c7..8de7a09fc01689b513bad4c5bf5a5db9bad1bca3 100644
--- a/plugins/mbm/mm-broadband-bearer-mbm.c
+++ b/plugins/mbm/mm-broadband-bearer-mbm.c
@@ -359,22 +359,35 @@ authenticate (GTask *task)
 
     /* Both user and password are required; otherwise firmware returns an error */
     if (user || password) {
-        gchar *command;
-        gchar *encoded_user;
-        gchar *encoded_password;
+        g_autofree gchar  *command = NULL;
+        g_autofree gchar  *user_enc = NULL;
+        g_autofree gchar  *password_enc = NULL;
+        GError            *error = NULL;
+
+        user_enc = mm_modem_charset_str_from_utf8 (user,
+                                                   mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (ctx->modem)),
+                                                   FALSE,
+                                                   &error);
+        if (!user_enc) {
+            g_prefix_error (&error, "Couldn't convert user to current charset: ");
+            g_task_return_error (task, error);
+            g_object_unref (task);
+            return;
+        }
 
-        encoded_user = mm_broadband_modem_take_and_convert_to_current_charset (MM_BROADBAND_MODEM (ctx->modem),
-                                                                               g_strdup (user));
-        encoded_password = mm_broadband_modem_take_and_convert_to_current_charset (MM_BROADBAND_MODEM (ctx->modem),
-                                                                                   g_strdup (password));
+        password_enc = mm_modem_charset_str_from_utf8 (password,
+                                                       mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (ctx->modem)),
+                                                       FALSE,
+                                                       &error);
+        if (!password_enc) {
+            g_prefix_error (&error, "Couldn't convert password to current charset: ");
+            g_task_return_error (task, error);
+            g_object_unref (task);
+            return;
+        }
 
         command = g_strdup_printf ("AT*EIAAUW=%d,1,\"%s\",\"%s\"",
-                                   ctx->cid,
-                                   encoded_user ? encoded_user : "",
-                                   encoded_password ? encoded_password : "");
-        g_free (encoded_user);
-        g_free (encoded_password);
-
+                                   ctx->cid, user_enc, password_enc);
         mm_base_modem_at_command_full (ctx->modem,
                                        ctx->primary,
                                        command,
@@ -384,7 +397,6 @@ authenticate (GTask *task)
                                        g_task_get_cancellable (task),
                                        (GAsyncReadyCallback) authenticate_ready,
                                        task);
-        g_free (command);
         return;
     }
 
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
index 873a1059efafaf83de981d1db2f392f9b7316423..fc67104f144d891e728f3551f4401e6aabcce42a 100644
--- a/src/mm-broadband-modem.c
+++ b/src/mm-broadband-modem.c
@@ -4800,27 +4800,37 @@ cops_set_ready (MMBaseModem  *self,
 }
 
 static void
-cops_ascii_set_ready (MMBaseModem  *self,
+cops_ascii_set_ready (MMBaseModem  *_self,
                       GAsyncResult *res,
                       GTask        *task)
 {
-    GError *error = NULL;
+    MMBroadbandModem  *self = MM_BROADBAND_MODEM (_self);
+    g_autoptr(GError)  error = NULL;
 
-    if (!mm_base_modem_at_command_full_finish (MM_BASE_MODEM (self), res, &error)) {
+    if (!mm_base_modem_at_command_full_finish (_self, res, &error)) {
         /* If it failed with an unsupported error, retry with current modem charset */
         if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED)) {
-            gchar *operator_id;
-            gchar *operator_id_current_charset;
+            g_autoptr(GError)  enc_error = NULL;
+            g_autofree gchar  *operator_id_enc = NULL;
+            gchar             *operator_id;
 
+            /* try to encode to current charset */
             operator_id = g_task_get_task_data (task);
-            operator_id_current_charset = mm_broadband_modem_take_and_convert_to_current_charset (MM_BROADBAND_MODEM (self), g_strdup (operator_id));
+            operator_id_enc = mm_modem_charset_str_from_utf8 (operator_id, self->priv->modem_current_charset, FALSE, &enc_error);
+            if (!operator_id_enc) {
+                mm_obj_dbg (self, "couldn't convert operator id to current charset: %s", enc_error->message);
+                g_task_return_error (task, g_steal_pointer (&error));
+                g_object_unref (task);
+                return;
+            }
 
-            if (g_strcmp0 (operator_id, operator_id_current_charset) != 0) {
-                gchar *command;
+            /* retry only if encoded string is different to the non-encoded one */
+            if (g_strcmp0 (operator_id, operator_id_enc) != 0) {
+                g_autofree gchar *command = NULL;
 
-                command = g_strdup_printf ("+COPS=1,2,\"%s\"", operator_id_current_charset);
-                mm_base_modem_at_command_full (MM_BASE_MODEM (self),
-                                               mm_base_modem_peek_best_at_port (MM_BASE_MODEM (self), NULL),
+                command = g_strdup_printf ("+COPS=1,2,\"%s\"", operator_id_enc);
+                mm_base_modem_at_command_full (_self,
+                                               mm_base_modem_peek_best_at_port (_self, NULL),
                                                command,
                                                120,
                                                FALSE,
@@ -4828,16 +4838,10 @@ cops_ascii_set_ready (MMBaseModem  *self,
                                                g_task_get_cancellable (task),
                                                (GAsyncReadyCallback)cops_set_ready,
                                                task);
-                g_error_free (error);
-                g_free (operator_id_current_charset);
-                g_free (command);
                 return;
             }
-            /* operator id string would be the same on the current charset,
-             * so fallback and return the not supported error */
-            g_free (operator_id_current_charset);
         }
-        g_task_return_error (task, error);
+        g_task_return_error (task, g_steal_pointer (&error));
     } else
         g_task_return_boolean (task, TRUE);
     g_object_unref (task);
@@ -7311,11 +7315,17 @@ sms_text_part_list_ready (MMBroadbandModem *self,
     ctx = g_task_get_task_data (task);
 
     while (g_match_info_matches (match_info)) {
-        MMSmsPart *part;
-        guint matches, idx;
-        gchar *number, *timestamp, *text, *ucs2_text, *stat;
-        gsize ucs2_len = 0;
-        GByteArray *raw;
+        MMSmsPart            *part;
+        guint                 matches;
+        guint                 idx;
+        g_autofree gchar      *number_enc = NULL;
+        g_autofree gchar      *number = NULL;
+        g_autofree gchar      *timestamp = NULL;
+        g_autofree gchar      *text_enc = NULL;
+        g_autofree gchar      *text = NULL;
+        g_autofree gchar      *stat = NULL;
+        g_autoptr(GByteArray)  raw = NULL;
+        g_autoptr(GError)      inner_error = NULL;
 
         matches = g_match_info_get_match_count (match_info);
         if (matches != 7) {
@@ -7336,39 +7346,44 @@ sms_text_part_list_ready (MMBroadbandModem *self,
         }
 
         /* Get and parse number */
-        number = mm_get_string_unquoted_from_match_info (match_info, 3);
-        if (!number) {
+        number_enc = mm_get_string_unquoted_from_match_info (match_info, 3);
+        if (!number_enc) {
             mm_obj_dbg (self, "failed to get message sender number");
-            g_free (stat);
             goto next;
         }
-
-        number = mm_broadband_modem_take_and_convert_to_utf8 (MM_BROADBAND_MODEM (self),
-                                                              number);
+        number = mm_modem_charset_str_to_utf8 (number_enc, -1, self->priv->modem_current_charset, FALSE, &inner_error);
+        if (!number) {
+            mm_obj_dbg (self, "failed to convert message sender number to UTF-8: %s", inner_error->message);
+            goto next;
+        }
 
         /* Get and parse timestamp (always expected in ASCII) */
         timestamp = mm_get_string_unquoted_from_match_info (match_info, 5);
+        if (timestamp && !g_str_is_ascii (timestamp)) {
+            mm_obj_dbg (self, "failed to parse input timestamp as ASCII");
+            goto next;
+        }
 
         /* Get and parse text */
-        text = mm_broadband_modem_take_and_convert_to_utf8 (MM_BROADBAND_MODEM (self),
-                                                            g_match_info_fetch (match_info, 6));
+        text_enc = g_match_info_fetch (match_info, 6);
+        text = mm_modem_charset_str_to_utf8 (text_enc, -1, self->priv->modem_current_charset, FALSE, &inner_error);
+        if (!text) {
+            mm_obj_dbg (self, "failed to convert message text to UTF-8: %s", inner_error->message);
+            goto next;
+        }
 
         /* The raw SMS data can only be GSM, UCS2, or unknown (8-bit), so we
          * need to convert to UCS2 here.
          */
-        ucs2_text = g_convert (text, -1, "UCS-2BE//TRANSLIT", "UTF-8", NULL, &ucs2_len, NULL);
-        g_assert (ucs2_text);
-        raw = g_byte_array_sized_new (ucs2_len);
-        g_byte_array_append (raw, (const guint8 *) ucs2_text, ucs2_len);
-        g_free (ucs2_text);
+        raw = mm_modem_charset_bytearray_from_utf8 (text, MM_MODEM_CHARSET_UCS2, FALSE, NULL);
+        g_assert (raw);
 
         /* all take() methods pass ownership of the value as well */
-        part = mm_sms_part_new (idx,
-                                sms_pdu_type_from_str (stat));
-        mm_sms_part_take_number (part, number);
-        mm_sms_part_take_timestamp (part, timestamp);
-        mm_sms_part_take_text (part, text);
-        mm_sms_part_take_data (part, raw);
+        part = mm_sms_part_new (idx, sms_pdu_type_from_str (stat));
+        mm_sms_part_take_number (part, g_steal_pointer (&number));
+        mm_sms_part_take_timestamp (part, g_steal_pointer (&timestamp));
+        mm_sms_part_take_text (part, g_steal_pointer (&text));
+        mm_sms_part_take_data (part, g_steal_pointer (&raw));
         mm_sms_part_set_class (part, -1);
 
         mm_obj_dbg (self, "correctly parsed SMS list entry (%d)", idx);
@@ -7376,7 +7391,6 @@ sms_text_part_list_ready (MMBroadbandModem *self,
                                             part,
                                             sms_state_from_str (stat),
                                             ctx->list_storage);
-        g_free (stat);
 next:
         g_match_info_next (match_info, NULL);
     }
@@ -11890,35 +11904,14 @@ initialize (MMBaseModem *self,
 
 /*****************************************************************************/
 
-gchar *
-mm_broadband_modem_take_and_convert_to_utf8 (MMBroadbandModem *self,
-                                             gchar *str)
-{
-    /* should only be used AFTER current charset is set */
-    if (self->priv->modem_current_charset == MM_MODEM_CHARSET_UNKNOWN)
-        return str;
-
-    return mm_charset_take_and_convert_to_utf8 (str,
-                                                self->priv->modem_current_charset);
-}
-
-gchar *
-mm_broadband_modem_take_and_convert_to_current_charset (MMBroadbandModem *self,
-                                                        gchar *str)
-{
-    /* should only be used AFTER current charset is set */
-    if (self->priv->modem_current_charset == MM_MODEM_CHARSET_UNKNOWN)
-        return str;
-
-    return mm_utf8_take_and_convert_to_charset (str, self->priv->modem_current_charset);
-}
-
 MMModemCharset
 mm_broadband_modem_get_current_charset (MMBroadbandModem *self)
 {
     return self->priv->modem_current_charset;
 }
 
+/*****************************************************************************/
+
 gchar *
 mm_broadband_modem_create_device_identifier (MMBroadbandModem *self,
                                              const gchar *ati,
@@ -11940,7 +11933,6 @@ mm_broadband_modem_create_device_identifier (MMBroadbandModem *self,
                     MM_GDBUS_MODEM (self->priv->modem_dbus_skeleton))));
 }
 
-
 /*****************************************************************************/
 
 void
diff --git a/src/mm-broadband-modem.h b/src/mm-broadband-modem.h
index eafca857783ad617286e7499fec20fbf2eed0bd1..1f5acac3cc4e4a9012af0700a3a661d617baf8b0 100644
--- a/src/mm-broadband-modem.h
+++ b/src/mm-broadband-modem.h
@@ -100,18 +100,6 @@ MMBroadbandModem *mm_broadband_modem_new (const gchar *device,
                                           guint16 vendor_id,
                                           guint16 product_id);
 
-/* Convert the given string, which comes in the charset currently set in the
- * modem, to UTF-8. Given in the API so that subclasses can also use it directly.
- */
-gchar *mm_broadband_modem_take_and_convert_to_utf8 (MMBroadbandModem *self,
-                                                    gchar *str);
-
-/* Convert the given string, which comes in UTF-8, to the charset currently set
- * in the modem. Given in the API so that subclasses can also use it directly.
- */
-gchar *mm_broadband_modem_take_and_convert_to_current_charset (MMBroadbandModem *self,
-                                                               gchar *str);
-
 MMModemCharset mm_broadband_modem_get_current_charset (MMBroadbandModem *self);
 
 /* Create a unique device identifier string using the ATI and ATI1 replies and some