Index: ModemManager-0.4/Makefile.am
===================================================================
--- ModemManager-0.4.orig/Makefile.am
+++ ModemManager-0.4/Makefile.am
@@ -25,6 +25,9 @@ if WITH_POLKIT
 SUBDIRS += policy
 endif
 
+udevrulesdir = $(UDEV_BASE_DIR)/rules.d
+udevrules_DATA = 90-modemmanager.rules
+
 dbusservicedir = $(DBUS_SYS_DIR)
 dbusservice_DATA = ModemManager.conf
 
Index: ModemManager-0.4/src/mm-manager.c
===================================================================
--- ModemManager-0.4.orig/src/mm-manager.c
+++ ModemManager-0.4/src/mm-manager.c
@@ -14,9 +14,28 @@
  * Copyright (C) 2009 - 2010 Red Hat, Inc.
  */
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#define _GNU_SOURCE 1
+
 #include <string.h>
 #include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <linux/types.h>
+#include <net/if_arp.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/utsname.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
 #include <gmodule.h>
+
 #define G_UDEV_API_IS_SUBJECT_TO_CHANGE
 #include <gudev/gudev.h>
 #include <dbus/dbus-glib.h>
@@ -273,10 +292,12 @@ modem_valid (MMModem *modem, GParamSpec
 {
     MMManager *manager = MM_MANAGER (user_data);
 
-    if (mm_modem_get_valid (modem))
+
+    if (mm_modem_get_valid (modem)) {
         check_export_modem (manager, modem);
-    else
+    } else {
         remove_modem (manager, modem);
+    }
 }
 
 #define MANAGER_PLUGIN_TAG "manager-plugin"
@@ -773,7 +794,7 @@ device_added (MMManager *manager, GUdevD
         goto out;
     }
 
-    /* Success; now ask plugins if they can handle this port */    
+    /* Success; now ask plugins if they can handle this port */
     info = supports_info_new (manager, subsys, name, physdev_path);
     g_hash_table_insert (priv->supports, g_strdup (key), info);
 
@@ -794,8 +815,33 @@ out:
     g_free (key);
 }
 
+static const char *
+device_get_name (const char *sys_path) {
+	const char *pos;
+	char * sysname;
+        size_t len;
+
+        pos = strrchr(sys_path, '/');
+        if (pos == NULL)
+                return NULL;
+
+        sysname = strdup(&pos[1]);
+        if (sysname == NULL)
+                return NULL;
+
+        /* some devices have '!' in their name, change that to '/' */
+        len = 0;
+        while (sysname[len] != '\0') {
+                if (sysname[len] == '!')
+                        sysname[len] = '/';
+                len++;
+        }
+
+	return sysname;
+}
+
 static void
-device_removed (MMManager *manager, GUdevDevice *device)
+device_removed (MMManager *manager, GUdevDevice *device, const char *subsystem, const char *sys_path)
 {
     MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
     MMModem *modem;
@@ -803,13 +849,16 @@ device_removed (MMManager *manager, GUde
     char *key;
     SupportsInfo *info;
 
-    g_return_if_fail (device != NULL);
-
     if (!g_slist_length (priv->plugins))
         return;
 
-    subsys = g_udev_device_get_subsystem (device);
-    name = g_udev_device_get_name (device);
+    if (device != NULL) {
+    	subsys = g_udev_device_get_subsystem (device);
+	name = g_udev_device_get_name (device);
+    } else {
+	subsys = subsystem;
+	name = device_get_name (sys_path);
+    }
 
     if (strcmp (subsys, "usb") != 0) {
         /* find_modem_for_port handles tty and net removal */
@@ -827,15 +876,18 @@ device_removed (MMManager *manager, GUde
          * device has been removed.  That way, if the device is reinserted later, we'll go through
          * the process of exporting it.
          */
-        const char *sysfs_path = g_udev_device_get_sysfs_path (device);
+        const char *sysfs_path;
+
+	if (device != NULL)
+		sysfs_path  = g_udev_device_get_sysfs_path (device);
+	else
+		sysfs_path = sys_path;
 
-        // g_debug ("Looking for a modem for removed device %s", sysfs_path);
         modem = find_modem_for_device (manager, sysfs_path);
         if (modem) {
-            g_debug ("Removing modem claimed by removed device %s", sysfs_path);
             remove_modem (manager, modem);
             return;
-        }
+	}
     }
 
     /* Maybe a plugin is checking whether or not the port is supported */
@@ -851,13 +903,159 @@ device_removed (MMManager *manager, GUde
     g_free (key);
 }
 
+static gboolean
+filter_udevevents (GIOChannel *source, GIOCondition condition, gpointer user_data)
+{
+	int fd;
+        int retval;
+        struct msghdr smsg;
+        struct cmsghdr *cmsg;
+        struct iovec iov;
+        struct ucred *cred;
+        char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+
+        char buf[4096];
+        size_t bufpos = 0;
+        const char *action = NULL;
+        gchar subsys[64];
+        gchar sysfs_path[4096];
+
+	GUdevDevice *device;
+	MMManagerPrivate *priv;
+        MMManager *self = MM_MANAGER (user_data);
+
+	priv = MM_MANAGER_GET_PRIVATE (self);
+
+        memset(buf, 0x00, sizeof (buf));
+
+        fd = g_io_channel_unix_get_fd (source);
+
+        iov.iov_base = &buf;
+        iov.iov_len = sizeof (buf);
+
+        memset(&smsg, 0x00, sizeof (struct msghdr));
+        smsg.msg_iov = &iov;
+        smsg.msg_iovlen = 1;
+        smsg.msg_control = cred_msg;
+        smsg.msg_controllen = sizeof (cred_msg);
+
+        retval = recvmsg (fd, &smsg, 0);
+        if (retval <  0) {
+                if (errno != EINTR)
+                        g_debug("Unable to receive message, errno=%d", errno);
+                goto out;
+        }
+        cmsg = CMSG_FIRSTHDR (&smsg);
+        cred = (struct ucred *) CMSG_DATA (cmsg);
+
+        if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
+                g_debug ("No sender credentials received, message ignored");
+                goto out;
+        }
+
+        if (cred->uid != 0) {
+                g_debug ("Sender uid=%i, message ignored", cred->uid);
+                goto out;
+        }
+
+        if (!strstr(buf, "@/")) {
+                g_debug ("invalid message format");
+                goto out;
+        }
+
+        while (bufpos < sizeof (buf)) {
+                size_t keylen;
+                char *key;
+
+                key = &buf[bufpos];
+                keylen = strlen(key);
+                if (keylen == 0)
+                        break;
+                bufpos += keylen + 1;
+
+		if (strncmp(key, "ACTION=", 7) == 0) {
+                        action = &key[7];
+		} else if (strncmp(key, "SUBSYSTEM=", 10) == 0) {
+			g_strlcpy (subsys, &key[10], sizeof (subsys));
+                } else if (strncmp(key, "DEVPATH=", 8) == 0) {
+                        g_snprintf (sysfs_path, sizeof (sysfs_path), "/sys%s", &key[8]);
+		}
+	}
+
+        if (!action) {
+                g_debug ("missing ACTION");
+                goto out;
+        }
+        if (sysfs_path[0] == '\0') {
+                g_debug("missing DEVPATH");
+                goto out;
+        }
+        if (subsys[0] == '\0') {
+                g_debug("missing SUBSYSTEM");
+                goto out;
+        }
+
+	device = g_udev_client_query_by_sysfs_path(priv->udev, sysfs_path);
+
+	if (strcmp (subsys, "tty") != 0 && strcmp (subsys, "net") != 0 && strcmp (subsys, "usb") != 0) {
+		goto out;
+	}
+
+        /* We only care about tty/net devices when adding modem ports,
+         * but for remove, also handle usb parent device remove events
+         */
+        if ((!strcmp (action, "add") || !strcmp (action, "move")) && strcmp (subsys, "usb") !=0 )
+                device_added (self, device);
+        else if (!strcmp (action, "remove")) {
+		// send sysfs_path and subsys directly to device_removed() since there is no caching
+                device_removed (self, device, subsys, sysfs_path);
+	}
+
+out:
+        return TRUE;
+}
+
+static gboolean
+init_udevsocket (MMManager *manager)
+{
+        int udev_socket;
+        struct sockaddr_un saddr;
+        socklen_t addrlen;
+        const int on = 1;
+        GIOChannel *udev_channel;
+
+        memset(&saddr, 0x00, sizeof(saddr));
+        saddr.sun_family = AF_LOCAL;
+        strcpy(&saddr.sun_path[1], "/org/freedesktop/modem_manager/udev_event");
+        addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
+
+        udev_socket = socket(AF_LOCAL, SOCK_DGRAM, 0);
+        if (udev_socket == -1) {
+                g_debug("init_udevsocket(): Couldn't open socket");
+		return FALSE;
+        }
+
+        if (bind(udev_socket, (struct sockaddr *) &saddr, addrlen) < 0) {
+		g_debug("Error binding udev_event socket: %s\n", strerror(errno));
+                return FALSE;
+        }
+        /* enable receiving of the sender credentials */
+        setsockopt(udev_socket, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
+
+        udev_channel = g_io_channel_unix_new (udev_socket);
+        g_io_add_watch (udev_channel, G_IO_IN, filter_udevevents, manager);
+        g_io_channel_unref (udev_channel);
+
+	return TRUE;
+}
+
 static void
 handle_uevent (GUdevClient *client,
                const char *action,
                GUdevDevice *device,
                gpointer user_data)
 {
-    MMManager *self = MM_MANAGER (user_data);
+	MMManager *self = MM_MANAGER (user_data);
 	const char *subsys;
 
 	g_return_if_fail (action != NULL);
@@ -874,7 +1072,7 @@ handle_uevent (GUdevClient *client,
 	if ((!strcmp (action, "add") || !strcmp (action, "move")) && strcmp (subsys, "usb") !=0 )
 		device_added (self, device);
 	else if (!strcmp (action, "remove"))
-		device_removed (self, device);
+		device_removed (self, device, NULL, NULL);
 }
 
 void
@@ -981,7 +1179,13 @@ mm_manager_init (MMManager *manager)
 
     priv->udev = g_udev_client_new (subsys);
     g_assert (priv->udev);
-    g_signal_connect (priv->udev, "uevent", G_CALLBACK (handle_uevent), manager);
+
+    if (init_udevsocket(manager)) {
+	g_debug("Connected successfully to the udev socket");
+    } else {
+	g_signal_connect (priv->udev, "uevent", G_CALLBACK (handle_uevent), manager);
+    }
+
 }
 
 static void
@@ -1039,7 +1243,7 @@ mm_manager_class_init (MMManagerClass *m
 									 &dbus_glib_mm_manager_object_info);
 
     dbus_g_error_domain_register (MM_SERIAL_ERROR, "org.freedesktop.ModemManager.Modem", MM_TYPE_SERIAL_ERROR);
-	dbus_g_error_domain_register (MM_MODEM_ERROR, "org.freedesktop.ModemManager.Modem", MM_TYPE_MODEM_ERROR);
+    dbus_g_error_domain_register (MM_MODEM_ERROR, "org.freedesktop.ModemManager.Modem", MM_TYPE_MODEM_ERROR);
     dbus_g_error_domain_register (MM_MODEM_CONNECT_ERROR, "org.freedesktop.ModemManager.Modem", MM_TYPE_MODEM_CONNECT_ERROR);
     dbus_g_error_domain_register (MM_MOBILE_ERROR, "org.freedesktop.ModemManager.Modem.Gsm", MM_TYPE_MOBILE_ERROR);
 }
Index: ModemManager-0.4/90-modemmanager.rules
===================================================================
--- /dev/null
+++ ModemManager-0.4/90-modemmanager.rules
@@ -0,0 +1,2 @@
+# pass all events to the modem_manager
+RUN+="socket:@/org/freedesktop/modem_manager/udev_event"
