diff --git a/src/nm-gsm-device.c b/src/nm-gsm-device.c
index ddabba8..a06af24 100644
--- a/src/nm-gsm-device.c
+++ b/src/nm-gsm-device.c
@@ -50,6 +50,8 @@ typedef struct {
 
 	guint reg_tries;
 	guint init_tries;
+	gboolean init_ok;
+	guint pin_tries;
 
 	gboolean needs_cgreg;
 	gboolean checked_cgmm;
@@ -84,7 +86,9 @@ const gchar *modem_init_sequences[] = {
 static void enter_pin (NMGsmDevice *device, NMGsmSecret secret_type, gboolean retry);
 static void manual_registration (NMGsmDevice *device);
 static void automatic_registration (NMGsmDevice *device);
+static void init_modem_full (NMGsmDevice *device);
 static void init_modem (NMSerialDevice *device);
+static void check_pin (NMGsmDevice *self);
 
 NMGsmDevice *
 nm_gsm_device_new (const char *udi,
@@ -381,6 +385,7 @@ automatic_registration_response (NMSerialDevice *device,
 	NMGsmDevicePrivate *priv = NM_GSM_DEVICE_GET_PRIVATE (device);
 
 	switch (reply_index) {
+	case 4:
 	case 0:
 		/* Try autoregistration a few times here because the card is actually
 		 * responding to the query and thus we aren't waiting as long for
@@ -412,7 +417,7 @@ automatic_registration_response (NMSerialDevice *device,
 		                         NM_DEVICE_STATE_FAILED,
 		                         NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED);
 		break;
-	case 4:
+	case 5:
 		nm_info ("Registered on Roaming network");
 		automatic_registration_get_network (NM_GSM_DEVICE (device));
 		break;
@@ -444,8 +449,8 @@ static void
 automatic_registration (NMGsmDevice *device)
 {
 	NMGsmDevicePrivate *priv = NM_GSM_DEVICE_GET_PRIVATE (device);
-	const char *creg_responses[] = { "+CREG: 0,0", "+CREG: 0,1", "+CREG: 0,2", "+CREG: 0,3", "+CREG: 0,5", NULL };
-	const char *cgreg_responses[] = { "+CGREG: 0,0", "+CGREG: 0,1", "+CGREG: 0,2", "+CGREG: 0,3", "+CGREG: 0,5", NULL };
+	const char *creg_responses[] = { "+CREG: 0,0", "+CREG: 0,1", "+CREG: 0,2", "+CREG: 0,3", "+CREG: 0,4", "+CREG: 0,5", NULL };
+	const char *cgreg_responses[] = { "+CGREG: 0,0", "+CGREG: 0,1", "+CGREG: 0,2", "+CGREG: 0,3", "+CGREG: 0,4", "+CGREG: 0,5", NULL };
 	const char *terminators[] = { "OK", "ERROR", "ERR", NULL };
 
 	if (priv->needs_cgreg)
@@ -480,7 +485,8 @@ get_model_done (NMSerialDevice *device,
 	priv->checked_cgmm = TRUE;
 
 	switch (reply_index) {
-	case 0:
+	case 0: /* Huawei E160G */
+	case 1: /* Ericsson F3507g */
 		priv->needs_cgreg = TRUE;
 		break;
 	default:
@@ -498,7 +504,7 @@ power_up_response (NMSerialDevice *device,
 {
 	NMGsmDevice *self = NM_GSM_DEVICE (device);
 	NMGsmDevicePrivate *priv = NM_GSM_DEVICE_GET_PRIVATE (self);
-	const char *responses[] = { "E160G", NULL };
+	const char *responses[] = { "E160G", "F3507g", NULL };
 	const char *terminators[] = { "OK", "ERROR", "ERR", NULL };
 
 	/* Get the model the first time */
@@ -523,8 +529,12 @@ init_full_done (NMSerialDevice *device,
                 const char *reply,
                 gpointer user_data)
 {
+	NMGsmDevice *self = NM_GSM_DEVICE (device);
+	NMGsmDevicePrivate *priv = NM_GSM_DEVICE_GET_PRIVATE (self);
+
 	switch (reply_index) {
 	case 0:
+		priv->init_ok = TRUE;
 		power_up (NM_GSM_DEVICE (device));
 		break;
 	case -1:
@@ -534,10 +544,29 @@ init_full_done (NMSerialDevice *device,
 		                         NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
 		break;
 	default:
-		nm_warning ("Modem second stage initialization failed");
-		nm_device_state_changed (NM_DEVICE (device),
-		                         NM_DEVICE_STATE_FAILED,
-		                         NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
+		if (priv->init_ok) {
+			/* If the successful init string from before PIN checking failed for
+			 * some reason, try all the init strings again.
+			 */
+			priv->init_ok = FALSE;
+
+			/* But don't try the first init string twice if it was previously
+			 * successful, but has now failed for some reason.
+			 */
+			priv->init_tries = (priv->init_tries > 0) ? 0 : 1;
+		} else
+			priv->init_tries++;
+
+		if (modem_init_sequences[priv->init_tries] != NULL) {
+			nm_warning ("Trying alternate modem initialization (%d)",
+			            priv->init_tries);
+			init_modem_full (self);
+		} else {
+			nm_warning ("Modem second stage initialization failed");
+			nm_device_state_changed (NM_DEVICE (device),
+			                         NM_DEVICE_STATE_FAILED,
+			                         NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
+		}
 		return;
 	}
 }
@@ -548,9 +577,9 @@ init_modem_full (NMGsmDevice *device)
 	NMGsmDevicePrivate *priv = NM_GSM_DEVICE_GET_PRIVATE (device);
 	const char *responses[] = { "OK", "ERROR", "ERR", NULL };
 
-	/* Send E0 too because some devices turn echo back on after CPIN which
-	 * just breaks stuff since echo-ed commands are interpreted as replies.
-	 * rh #456770
+	/* Make sure that E0 gets sent here again, because some devices turn echo
+	 * back on after CPIN which just breaks stuff since echo-ed commands are
+	 * interpreted as replies. (rh #456770)
 	 */
 	modem_wait_for_reply (device, modem_init_sequences[priv->init_tries], 10, responses, responses, init_full_done, NULL);
 }
@@ -647,22 +676,58 @@ enter_pin (NMGsmDevice *device, NMGsmSecret secret_type, gboolean retry)
 	}
 }
 
+static gboolean
+check_pin_again (gpointer data)
+{
+	check_pin (NM_GSM_DEVICE (data));
+	return FALSE;
+}
+
+static void
+schedule_check_pin_again (NMGsmDevice *self)
+{
+	NMGsmDevicePrivate *priv = NM_GSM_DEVICE_GET_PRIVATE (self);
+
+	if (priv->pending_id)
+		g_source_remove (priv->pending_id);
+
+	priv->pending_id = g_timeout_add_seconds (1, check_pin_again, self);
+}
+
 static void
 check_pin_done (NMSerialDevice *device,
                 int reply_index,
                 const char *reply,
                 gpointer user_data)
 {
+	NMGsmDevicePrivate *priv = NM_GSM_DEVICE_GET_PRIVATE (device);
+
 	switch (reply_index) {
 	case 0:
+		priv->pin_tries = 0;
 		init_modem_full (NM_GSM_DEVICE (device));
 		break;
 	case 1:
+		priv->pin_tries = 0;
 		enter_pin (NM_GSM_DEVICE (device), NM_GSM_SECRET_PIN, FALSE);
 		break;
 	case 2:
+		priv->pin_tries = 0;
 		enter_pin (NM_GSM_DEVICE (device), NM_GSM_SECRET_PUK, FALSE);
 		break;
+	case 3:
+	case 4:
+		/* Try the pin a few times; sometimes the error is transient */
+		if (priv->pin_tries++ < 4) {
+			schedule_check_pin_again (NM_GSM_DEVICE (device));
+		} else {
+			priv->pin_tries = 0;
+			nm_warning ("PIN checking failed to many times");
+			nm_device_state_changed (NM_DEVICE (device),
+			                         NM_DEVICE_STATE_FAILED,
+			                         NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED);
+		}
+		break;
 	case -1:
 		nm_warning ("PIN checking timed out");
 		nm_device_state_changed (NM_DEVICE (device),
@@ -697,6 +762,7 @@ init_done (NMSerialDevice *device,
 
 	switch (reply_index) {
 	case 0:
+		priv->init_ok = TRUE;
 		check_pin (NM_GSM_DEVICE (device));
 		break;
 	case -1:
@@ -746,6 +812,9 @@ real_act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
 	}
 
 	NM_GSM_DEVICE_GET_PRIVATE (device)->init_tries = 0;
+	NM_GSM_DEVICE_GET_PRIVATE (device)->init_ok = FALSE;
+	NM_GSM_DEVICE_GET_PRIVATE (device)->pin_tries = 0;
+	NM_GSM_DEVICE_GET_PRIVATE (device)->reg_tries = 0;
 
 	id = nm_serial_device_flash (serial_device, 100, (NMSerialFlashFn) init_modem, NULL);
 	if (!id)
diff --git a/src/nm-hal-manager.c b/src/nm-hal-manager.c
index c5fbf1c..30c6cdc 100644
--- a/src/nm-hal-manager.c
+++ b/src/nm-hal-manager.c
@@ -130,6 +130,29 @@ nm_get_device_driver_name (LibHalContext *ctx, const char *origdev_udi)
 	return driver_name;
 }
 
+/* Returns the parent if the device is a Sony Ericsson 'mbm'-style device */
+static char *
+is_mbm (LibHalContext *ctx, const char *udi)
+{
+	guint32 vendor_id = 0, product_id = 0;
+	char *parent;
+
+	parent = libhal_device_get_property_string (ctx, udi, "info.parent", NULL);
+	if (!parent)
+		return NULL;
+
+	vendor_id = libhal_device_get_property_int (ctx, parent, "usb.vendor_id", NULL);
+	product_id = libhal_device_get_property_int (ctx, parent, "usb.product_id", NULL);
+
+	if (   (vendor_id == 0x0bdb && product_id == 0x1900)  /* SE F3507g */
+	    || (vendor_id == 0x0fce && product_id == 0xd0cf)  /* SE MD300 */
+	    || (vendor_id == 0x413c && product_id == 0x8147)) /* Dell 5530 HSDPA */
+		return parent;
+
+	libhal_free_string (parent);
+	return NULL;
+}
+
 /* Wired device creator */
 
 static gboolean
@@ -159,9 +182,9 @@ wired_device_creator (NMHalManager *self,
                       gboolean managed)
 {
 	NMHalManagerPrivate *priv = NM_HAL_MANAGER_GET_PRIVATE (self);
-	GObject *device;
-	char *iface;
-	char *driver;
+	GObject *device = NULL;
+	char *iface, *driver, *parent;
+	gboolean mbm = FALSE;
 
 	iface = libhal_device_get_property_string (priv->hal_ctx, udi, "net.interface", NULL);
 	if (!iface) {
@@ -170,11 +193,21 @@ wired_device_creator (NMHalManager *self,
 	}
 
 	driver = nm_get_device_driver_name (priv->hal_ctx, origdev_udi);
-	device = (GObject *) nm_device_ethernet_new (udi, iface, driver, managed);
+
+	/* Special handling of Ericsson F3507g 'mbm' devices; ignore the
+	 * cdc-ether device that it provides since we don't use it yet.
+	 */
+	if (!strcmp (driver, "cdc_ether")) {
+		parent = is_mbm (priv->hal_ctx, udi);
+		mbm = !!parent;
+		libhal_free_string (parent);
+	}
+
+	if (!mbm)
+		device = (GObject *) nm_device_ethernet_new (udi, iface, driver, managed);
 
 	libhal_free_string (iface);
 	g_free (driver);
-
 	return device;
 }
 
@@ -614,7 +647,25 @@ modem_device_creator (NMHalManager *self,
 				goto out;
 			}
 		}
-		g_free (parent);
+		libhal_free_string (parent);
+	}
+
+	/* Special handling of Ericsson F3507g 'mbm' devices; already handled by
+	 * ModemManager more correctly in HEAD.
+	 */
+	if (type_gsm && !strcmp (driver, "cdc_acm")) {
+		char *parent;
+		guint32 usb_interface;
+
+		parent = is_mbm (priv->hal_ctx, udi);
+		if (parent) {
+			usb_interface = libhal_device_get_property_int (priv->hal_ctx, parent, "usb.interface.number", NULL);
+			if (usb_interface != 1) {
+				libhal_free_string (parent);
+				goto out;
+			}
+			libhal_free_string (parent);
+		}
 	}
 
 	if (type_gsm) {
