diff -urN ../linux-2.6.16-rc1/net/Kconfig net/Kconfig
--- ../linux-2.6.16-rc1/net/Kconfig	2006-01-17 08:44:47.000000000 +0100
+++ net/Kconfig	2006-01-24 20:55:56.000000000 +0100
@@ -27,6 +27,7 @@
 
 menu "Networking options"
 
+source "net/netlink/Kconfig"
 source "net/packet/Kconfig"
 source "net/unix/Kconfig"
 source "net/xfrm/Kconfig"
diff -urN ../linux-2.6.16-rc1/net/netlink/af_netlink.c net/netlink/af_netlink.c
--- ../linux-2.6.16-rc1/net/netlink/af_netlink.c	2006-01-24 20:55:09.000000000 +0100
+++ net/netlink/af_netlink.c	2006-01-24 20:56:29.000000000 +0100
@@ -1069,6 +1069,41 @@
 		wake_up_interruptible(&nlk->wait);
 }
 
+#if defined(CONFIG_NLDEV_MODULE) || defined(CONFIG_NLDEV)
+
+/*
+  create a duplicated skbuff, and send it to our if
+*/
+
+static int nldev_send(struct sk_buff* skb, char* if_name)
+{
+    struct sk_buff *nskb;
+    struct net_device *nl_if;
+    int err;
+
+    nskb = skb_copy(skb, GFP_ATOMIC);
+
+    nl_if = dev_get_by_name(if_name);
+    /* interface not found */
+    if (!nl_if) {
+	return -ENOENT;
+    }
+    if ((nl_if->flags & IFF_UP) != IFF_UP)
+	    return -ENETDOWN;
+    
+    err = dev_open(nl_if);
+    if (err) {
+	printk("problem openning interface\n");
+	return err;
+    }
+    nskb->dev = nl_if;
+    err = dev_queue_xmit(nskb);
+    kfree_skb(nskb);
+    dev_put(nl_if); // decrease the refcnt
+    return err; 
+}
+#endif
+
 static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
 			   struct msghdr *msg, size_t len)
 {
@@ -1141,10 +1176,15 @@
 		goto out;
 	}
 
+#if defined(CONFIG_NLDEV_MODULE) || defined(CONFIG_NLDEV)
+		nldev_send(skb, "netlink");
+#endif
+
 	if (dst_group) {
 		atomic_inc(&skb->users);
 		netlink_broadcast(sk, skb, dst_pid, dst_group, GFP_KERNEL);
 	}
+
 	err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT);
 
 out:
@@ -1184,6 +1224,10 @@
 	skb->h.raw = skb->data;
 	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 
+#if defined(CONFIG_NLDEV_MODULE) || defined(CONFIG_NLDEV)	
+	nldev_send(skb, "netlink");
+#endif
+
 	if (msg->msg_name) {
 		struct sockaddr_nl *addr = (struct sockaddr_nl*)msg->msg_name;
 		addr->nl_family = AF_NETLINK;
diff -urN ../linux-2.6.16-rc1/net/netlink/Kconfig net/netlink/Kconfig
--- ../linux-2.6.16-rc1/net/netlink/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ net/netlink/Kconfig	2006-01-24 20:56:22.000000000 +0100
@@ -0,0 +1,10 @@
+#
+# Netlink sniffing interface
+#
+
+
+config NLDEV
+	tristate "Netlink virtual device"
+	default n
+	---help---
+	  Netlink virtual interface with sniffing hook in af_netlink.c
diff -urN ../linux-2.6.16-rc1/net/netlink/Makefile net/netlink/Makefile
--- ../linux-2.6.16-rc1/net/netlink/Makefile	2006-01-17 08:44:47.000000000 +0100
+++ net/netlink/Makefile	2006-01-24 20:56:04.000000000 +0100
@@ -3,3 +3,4 @@
 #
 
 obj-y  				:= af_netlink.o attr.o genetlink.o
+obj-$(CONFIG_NLDEV) 		+= nldev.o
diff -urN ../linux-2.6.16-rc1/net/netlink/nldev.c net/netlink/nldev.c
--- ../linux-2.6.16-rc1/net/netlink/nldev.c	1970-01-01 01:00:00.000000000 +0100
+++ net/netlink/nldev.c	2006-01-24 20:56:34.000000000 +0100
@@ -0,0 +1,141 @@
+/* 
+ *  New net interface register nldev
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_arp.h>
+
+#define NLDEV_NAME "netlink"
+#define NLDEVHDR_SIZE	sizeof(struct nldevhdr)
+
+static struct net_device nl_dev = { NLDEV_NAME };
+static struct sk_buff_head nldev_queue;
+
+static int nldev_event(struct notifier_block *unused, unsigned long event, void *ptr);
+static struct notifier_block nldev_notifier_block = {
+        .notifier_call = nldev_event,
+};
+
+static int nldev_event(struct notifier_block *unused, unsigned long event, void *ptr)
+{
+        if (event == NETDEV_DOWN)
+                nl_dev.flags &= ~IFF_UP;
+
+        if (event == NETDEV_UP)
+                nl_dev.flags |= IFF_UP;
+
+
+        return NOTIFY_DONE;
+}
+
+/* nldev device open */
+static int 
+nldev_open(struct net_device *dev){
+	// unset __LINK_STATE_XOFF state bit
+	netif_start_queue(dev);
+	return 0;
+}
+
+/* nldev device close */
+static int 
+nldev_close(struct net_device *dev){
+	netif_stop_queue(dev);
+	return 0;
+}
+
+/* nldev send */
+static int 
+nldev_xmit(struct sk_buff *skb, struct net_device *dev){
+	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
+	stats->rx_bytes += skb->len;
+	stats->rx_packets++;
+	return 0;
+}
+
+/* nldev stats */
+static struct net_device_stats *
+get_stats(struct net_device *dev)
+{
+	return (struct net_device_stats *)dev->priv;
+}
+
+/* init functions */
+static int nldev_init(struct net_device *dev)
+{
+	dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
+	if (dev->priv == NULL)
+		return -ENOMEM;
+	memset(dev->priv, 0, sizeof(struct net_device_stats));
+	dev->get_stats = get_stats;
+
+	skb_queue_head_init(&nldev_queue);
+
+	return 0;
+}
+
+static void nldev_uninit(struct net_device *dev)
+{
+	if (dev->priv)
+		kfree(dev->priv);
+
+	skb_queue_purge(&nldev_queue);
+}
+
+
+/* module functions */
+static int __init
+nldev_create(void){
+	struct net_device *dev = &nl_dev;
+	int err = - EINVAL;
+
+	dev->type               = ARPHRD_NONE;
+	dev->hard_start_xmit	= nldev_xmit;
+	dev->init		= nldev_init;
+	dev->uninit		= nldev_uninit;
+	dev->open               = nldev_open;
+	dev->stop               = nldev_close;
+	dev->mtu                = 32872;
+	dev->features		= NETIF_F_FRAGLIST | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA;
+
+	/* register */
+	if ((err = register_netdev(dev)) != 0) {
+		printk(KERN_ERR"nldev: device register failed\n");
+		goto fail_netdev;
+	}
+  
+        /* register to receive netdevice events */
+        err = register_netdevice_notifier(&nldev_notifier_block);
+        if (err < 0) {
+                printk(KERN_ERR"error registering nldev notifier\n");
+                goto fail_netdev;
+        }
+
+	/* device up */
+	rtnl_lock();
+	if ((err = dev_open(dev)) < 0) {
+		printk(KERN_ERR"nldev: open device failed\n");
+		goto fail_open;
+	}
+	rtnl_unlock();
+
+	return 0;
+
+ fail_open:
+	rtnl_unlock();
+ fail_netdev:
+	return err;
+}
+
+static void __exit
+nldev_destroy(void){
+        unregister_netdevice_notifier(&nldev_notifier_block);
+	unregister_netdev(&nl_dev);
+}
+
+module_init(nldev_create);
+module_exit(nldev_destroy);
+
+MODULE_LICENSE("GPL");
