diff --git a/src/mm-errors.c b/src/mm-errors.c
index 6448b80..03aa7fa 100644
--- a/src/mm-errors.c
+++ b/src/mm-errors.c
@@ -72,6 +72,8 @@ mm_modem_error_get_type (void)
             ENUM_ENTRY (MM_MODEM_ERROR_CONNECTED,               "Connected"),
             ENUM_ENTRY (MM_MODEM_ERROR_DISCONNECTED,            "Disconnected"),
             ENUM_ENTRY (MM_MODEM_ERROR_OPERATION_IN_PROGRESS,   "OperationInProgress"),
+            ENUM_ENTRY (MM_MODEM_ERROR_PIN_REJECTED,            "PinRejected"),
+            ENUM_ENTRY (MM_MODEM_ERROR_PUK_REJECTED,            "PukRejected"),
             { 0, 0, 0 }
         };
 
diff --git a/src/mm-errors.h b/src/mm-errors.h
index 4bf8eca..bf3ef50 100644
--- a/src/mm-errors.h
+++ b/src/mm-errors.h
@@ -38,7 +38,9 @@ enum {
     MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED = 1,
     MM_MODEM_ERROR_CONNECTED = 2,
     MM_MODEM_ERROR_DISCONNECTED = 3,
-    MM_MODEM_ERROR_OPERATION_IN_PROGRESS = 4
+    MM_MODEM_ERROR_OPERATION_IN_PROGRESS = 4,
+    MM_MODEM_ERROR_PIN_REJECTED = 10,
+    MM_MODEM_ERROR_PUK_REJECTED = 11
 };
 
 #define MM_MODEM_ERROR (mm_modem_error_quark ())
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index 55d75f6..6cdaf86 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -747,8 +752,45 @@ send_puk_done (MMSerialPort *port,
 {
     MMCallbackInfo *info = (MMCallbackInfo *) user_data;
 
-    if (error)
+    if (response)
+    {
+        /* we don't check the GError *error parameter in the first place, because */
+        /* the answer for a wrong PUK (or parsing it) takes very long sometimes, */
+        /* therefore would be a timeout GError */
+
+        if (strcmp(response->str, "")==0)
+        {
+            /* Success! */
+            /* Empty response string means the modem has sent "OK" */
+            g_message ("PUK accepted/new PIN set");
+        }
+        else
+        {
+            g_message ("Send PUK failed. Response: %s", response->str);
+
+            /* the ZTE MF628 doesn't seem to report an +CME ERROR: error code */
+            /* others send  Got failure code 13: SIM failure */
+
+            if (g_strrstr(response->str, "+CME ERROR") != NULL)
+            {
+                info->error = g_error_new (MM_MODEM_ERROR,
+                    MM_MODEM_ERROR_PUK_REJECTED,
+                    "Puk rejected");
+            }
+            else
+            {
+                info->error = g_error_new (MM_MODEM_ERROR,
+                    MM_MODEM_ERROR_GENERAL,
+                    "Send PUK response '%s'",
+                    response->str);
+            }
+        }
+    }
+    else if (error)
+    {
+        g_message ("Send PUK failed. Error: %s", error->message);
         info->error = g_error_copy (error);
+    }
     mm_callback_info_schedule (info);
 }
 
@@ -777,8 +819,50 @@ send_pin_done (MMSerialPort *port,
 {
     MMCallbackInfo *info = (MMCallbackInfo *) user_data;
 
-    if (error)
+    if (response)
+    {
+        /* we don't check the GError *error parameter in the first place, because */
+        /* the answer for a wrong PIN (or parsing it) takes very long sometimes, */
+        /* therefore would be a timeout GError */
+
+        if (strcmp(response->str, "")==0)
+        {
+            /* Success! */
+            /* Empty response string means the modem has sent "OK" */
+            g_message ("PIN accepted");
+        }
+        else
+        {
+            g_message ("Send PIN failed. Response: %s", response->str);
+
+            /* at least the ZTE MF628 doesn't seem to report an +CME ERROR: error code */
+            /* response->str is something like "#015#012+CME ERROR: incorrect password#015" */
+            /* perhaps we could also search for the pattern "incorrect password" */
+
+            /* Perhaps also look for '<CR><LF>+CME ERROR: SIM PUK required<CR><LF>' */
+
+            if (g_strrstr(response->str, "+CME ERROR") != NULL)
+            {
+                info->error = g_error_new (MM_MODEM_ERROR,
+                    MM_MODEM_ERROR_PIN_REJECTED,
+                    "PIN rejected");
+            }
+            else
+            {
+                info->error = g_error_new (MM_MODEM_ERROR,
+                    MM_MODEM_ERROR_GENERAL,
+                    "Send PIN response '%s'",
+                    response->str);
+            }
+        }
+    }
+    else if (error)
+    {
+        g_message ("Send PIN failed. Error: %s", error->message);
+
         info->error = g_error_copy (error);
+    }
+
     mm_callback_info_schedule (info);
 }
 
@@ -794,7 +878,7 @@ send_pin (MMModemGsmCard *modem,
 
     info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
     command = g_strdup_printf ("+CPIN=\"%s\"", pin);
-    mm_serial_port_queue_command (priv->primary, command, 3, send_pin_done, info);
+    mm_serial_port_queue_command (priv->primary, command, 10, send_pin_done, info);
     g_free (command);
 }
 
@@ -1203,7 +1287,10 @@ do_register (MMModemGsmNetwork *modem,
     if (network_id)
         command = g_strdup_printf ("+COPS=1,2,\"%s\"", network_id);
     else
-        command = g_strdup ("+COPS=0,,");
+    {
+        /* command = g_strdup ("+COPS=0,,"); */
+        command = g_strdup ("AT"); /* send dummy command, "+COPS=0,," seems to cause "no carrier" problems */
+    }
 
     /* Ref the callback info to ensure it stays alive for register_done() even
      * if the timeout triggers and ends registration (which calls the callback
@@ -1910,11 +1997,17 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data)
     const char *str;
     SimpleState state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "simple-connect-state"));
     gboolean need_pin = FALSE;
+    gboolean need_puk = FALSE;
 
     if (error) {
         if (g_error_matches (error, MM_MOBILE_ERROR, MM_MOBILE_ERROR_SIM_PIN)) {
             need_pin = TRUE;
             state = SIMPLE_STATE_CHECK_PIN;
+        }
+        else if (g_error_matches (error, MM_MOBILE_ERROR, MM_MOBILE_ERROR_SIM_PUK))
+        {
+            need_puk = TRUE;
+            state = SIMPLE_STATE_CHECK_PIN;
         } else {
             info->error = g_error_copy (error);
             goto out;
@@ -1937,6 +2030,16 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data)
                 mm_modem_gsm_card_send_pin (MM_MODEM_GSM_CARD (modem), str, simple_state_machine, info);
             else
                 info->error = g_error_copy (error);
+        }
+        else if (need_puk)
+        {
+            const gchar * puk = simple_get_string_property (info, "puk", &info->error);
+            str = simple_get_string_property (info, "pin", &info->error);
+            if (puk && str)
+                mm_modem_gsm_card_send_puk (MM_MODEM_GSM_CARD (modem), puk, str, simple_state_machine, info);
+            else
+                info->error = g_error_copy (error);
+
         } else {
             str = simple_get_string_property (info, "network_id", &info->error);
             state = SIMPLE_STATE_REGISTER;

