--- /dev/null
+diff -Nurb linux-2.6.22-591/drivers/net/Makefile linux-2.6.22-592/drivers/net/Makefile
+--- linux-2.6.22-591/drivers/net/Makefile 2008-01-02 13:56:37.000000000 -0500
++++ linux-2.6.22-592/drivers/net/Makefile 2008-01-23 17:45:01.000000000 -0500
+@@ -2,6 +2,7 @@
+ # Makefile for the Linux network (ethercard) device drivers.
+ #
+
++obj-y +=ztun.o shortbridge.o
+ obj-$(CONFIG_E1000) += e1000/
+ obj-$(CONFIG_E1000E) += e1000e/
+ obj-$(CONFIG_IBM_EMAC) += ibm_emac/
+diff -Nurb linux-2.6.22-591/drivers/net/shortbridge.c linux-2.6.22-592/drivers/net/shortbridge.c
+--- linux-2.6.22-591/drivers/net/shortbridge.c 1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6.22-592/drivers/net/shortbridge.c 2008-01-23 18:30:08.000000000 -0500
+@@ -0,0 +1,265 @@
++/*
++ * Shortbridge - short-circuited bridge
++ * Copyright (C) 2007
++ * Somebody
++ *
++ */
++
++#define MAX_SHORTBRIDGES 20
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/rtnetlink.h>
++#include <linux/if.h>
++#include <linux/if_ether.h>
++#include <linux/ctype.h>
++#include <net/net_namespace.h>
++#include <net/dst.h>
++#include <linux/nsproxy.h>
++
++
++struct shortbridge_entry {
++ struct list_head list; /* My bead in the rosary */
++ char first_dev[IFNAMSIZ];
++ struct net_device **dev1;
++ struct net_device **dev2;
++};
++
++static LIST_HEAD(shortbridges);
++
++int atoi(char *s) {
++ int sum=0;
++
++ while (*s) {
++ int digit=(*s)-48;
++ sum=10*sum+digit;
++ s++;
++ }
++ return sum;
++}
++
++static int sb_shortcircuit(struct net *net, const char *name0, const char *name1, char *number)
++{
++ struct shortbridge_entry *ent;
++ struct net_device *dev1, *dev2;
++ int numentries = atoi(number);
++ int i=0;
++
++ printk(KERN_CRIT "Short circuiting %s objects in device classes %s and %s\n",number,name0,name1);
++ ent = (struct shortbridge_entry *) kmalloc(sizeof(struct shortbridge_entry), GFP_KERNEL);
++ ent->dev1 = (struct net_device ** ) kmalloc(numentries * sizeof(struct net_device *), GFP_KERNEL);
++ ent->dev2 = (struct net_device ** ) kmalloc(numentries * sizeof(struct net_device *), GFP_KERNEL);
++
++ if (ent == NULL) {
++ printk(KERN_CRIT "kmalloc failed for shortbridge_entry");
++ return -ENOMEM;
++ }
++
++ for(i=0;i<numentries;i++) {
++ char name0i[10],name1i[10];
++ sprintf(name0i,"%s%d",name0,i);
++ sprintf(name1i,"%s%d",name1,i);
++
++ printk(KERN_CRIT "Device %s --> %s\n",name0i,name1i);
++
++ dev1 = dev_get_by_name(net, name0i);
++ if (dev1 == NULL) {
++ printk(KERN_CRIT "Can't find device %s (first device)",name0i);
++ return -ENOMEM;
++ }
++
++ dev2 = dev_get_by_name(net, name1i);
++ if (dev2 == NULL) {
++ printk(KERN_CRIT "Can't find device %s (second device)",name1i);
++ return -ENOMEM;
++ }
++
++
++ rtnl_lock();
++ ent->dev1[i] = dev1;
++ //dev1->hard_start_xmit = dev2->hard_start_xmit;
++ ent->dev2[i] = dev2;
++
++ rtnl_unlock();
++ }
++ list_add(&ent->list,&shortbridges);
++ return 0;
++}
++
++static int sb_newsb(const char *val, struct kernel_param *kp)
++{
++ char name0[IFNAMSIZ], name1[IFNAMSIZ],number[4];
++ const char *mid,*last;
++
++ int len, len0, len01,len1;
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++
++ /* Avoid frustration by removing trailing whitespace */
++ len = strlen(val);
++ while (isspace(val[len - 1]))
++ len--;
++
++ /* Split the string into 2 names */
++ mid = memchr(val, ',', len);
++ if (!mid) {
++ printk(KERN_CRIT "Error!\n");
++ return -EINVAL;
++ }
++
++ /* Get the first device name */
++ len0 = mid - val;
++ if (len0 > sizeof(name0) - 1)
++ len0 = sizeof(name0) - 1;
++ strncpy(name0, val, len0);
++ name0[len0] = '\0';
++
++ len-=(len0+1);
++
++ last = memchr(mid+1, ',', len);
++ if (!last) {
++ printk(KERN_CRIT "Error!\n");
++ return -EINVAL;
++ }
++
++ /* Get the second device name */
++ len01 = last - mid - 1;
++ if (len01 > sizeof(name0) - 1)
++ len0 = sizeof(name0) - 1;
++ strncpy(name1, mid+1, len01);
++ name1[len01] = '\0';
++
++
++ /* And the number device name */
++ len1 = len - (len01 + 1);
++ if (len1 > sizeof(name1) - 1)
++ len1 = sizeof(name1) - 1;
++ strncpy(number, last + 1, len1);
++ number[len1] = '\0';
++
++
++ return sb_shortcircuit(current->nsproxy->net_ns, name0, name1, number);
++}
++
++static int sb_delsb(const char *val, struct kernel_param *kp)
++{
++ char name[IFNAMSIZ];
++ int len;
++ struct list_head *cur, *tmp;
++ int err=0;
++
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++
++ /* Avoid frustration by removing trailing whitespace */
++ len = strlen(val);
++ while (isspace(val[len - 1]))
++ len--;
++
++ /* Get the device name */
++ if (len > sizeof(name) - 1)
++ {
++ printk(KERN_CRIT "shortbridge: Input string too long\n");
++ return -EINVAL;
++ }
++ strncpy(name, val, len);
++ name[len] = '\0';
++
++ rtnl_lock();
++ list_for_each_safe(cur, tmp, &shortbridges) {
++ struct shortbridge_entry *ent;
++ ent = list_entry (cur, struct shortbridge_entry, list);
++ if (!strcmp(name, ent->first_dev)) {
++ struct net_device *dev1 = ent->dev1;
++ dev1->hard_start_xmit = ent->dev1;
++ list_del (cur);
++ kfree (ent);
++ }
++ }
++ rtnl_unlock();
++
++ return err;
++}
++
++unsigned int sb_hook (struct sk_buff *skb, struct packet_type *pt,struct net_device *orig_dev) {
++ struct list_head *cur, *tmp;
++ /* Let's find our device - change this to use a hashtable instead of a list */
++ list_for_each_safe(cur, tmp, &shortbridges) {
++ struct shortbridge_entry *ent;
++ ent = list_entry (cur, struct shortbridge_entry, list);
++ if (skb->this_packet_is_stoned == 0){
++ unsigned int dev1,dev2;
++ unsigned int devb;
++ dev1=*((unsigned int *) (skb->dev->name));
++ dev2=*((unsigned int *) (ent->dev2[0]->name));
++ devb=*((unsigned int *) (ent->dev1[0]->name));
++
++ if (dev1 == dev2) {
++ //printk(KERN_CRIT "Splice: %s-->%s\n",skb->dev->name, ent->dev1[0]->name);
++ char *number=(char *) skb->dev->name+4;
++ int num=atoi(number);
++
++ skb->dev = ent->dev1[num];
++ skb->this_packet_is_stoned = 1;
++ }
++ else
++ if (dev1 == devb) {
++ //printk(KERN_CRIT "Splice: %s-->%s\n",skb->dev->name, ent->dev2[0]->name);
++ //
++ char *number=(char *) skb->dev->name+4;
++ int num=atoi(number);
++ skb->dev = ent->dev2[num];
++ skb->this_packet_is_stoned = 1;
++ }
++ }
++ }
++ return NET_RX_SUCCESS;
++}
++
++static struct packet_type sb_type = {
++ .type = __constant_htons(ETH_P_ALL),
++ .func = sb_hook
++};
++
++static int __init sb_init(void)
++{
++ //dev_add_pack(&sb_type);
++ printk(KERN_CRIT "Shortbridge device driver v0.1 loaded\n");
++ return 0;
++}
++
++static int sb_noget(char *buffer, struct kernel_param *kp)
++{
++ return 0;
++}
++
++static void sb_cleanup(void)
++{
++ struct list_head *cur, *tmp;
++ rtnl_lock();
++ list_for_each_safe(cur, tmp, &shortbridges) {
++ struct shortbridge_entry *ent;
++ struct net_device *dev1;
++ ent = list_entry (cur, struct shortbridge_entry, list);
++ dev1 = ent->dev1;
++ list_del (cur);
++ kfree (ent);
++ }
++ rtnl_unlock();
++ dev_remove_pack(&sb_type);
++}
++
++module_param_call(newsb, sb_newsb, sb_noget, NULL, S_IWUSR);
++module_param_call(delsb, sb_delsb, sb_noget, NULL, S_IWUSR);
++module_init(sb_init);
++module_exit(sb_cleanup);
++
++MODULE_DESCRIPTION("Short bridge device driver");
++MODULE_AUTHOR("Sapan Bhatia <sapan.bhatia@gmail.com>");
++MODULE_LICENSE("GPL");
+diff -Nurb linux-2.6.22-591/drivers/net/ztun.c linux-2.6.22-592/drivers/net/ztun.c
+--- linux-2.6.22-591/drivers/net/ztun.c 1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6.22-592/drivers/net/ztun.c 2008-01-23 18:28:47.000000000 -0500
+@@ -0,0 +1,154 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/rtnetlink.h>
++#include <linux/if.h>
++#include <linux/if_ether.h>
++#include <linux/ctype.h>
++#include <net/dst.h>
++#include <asm/current.h>
++#include <net/net_namespace.h>
++#include <linux/nsproxy.h>
++
++
++/* I don't know how to send packets, somebody steal them away from me */
++static int ztun_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct net_device_stats *stats = dev->priv;
++
++ stats->tx_packets++;
++ stats->tx_bytes += skb->len;
++
++ skb_orphan(skb);
++ if (skb->dst)
++ skb->dst = dst_pop(skb->dst); /* Allow for smart routing */
++
++ skb->pkt_type = PACKET_HOST;
++ netif_rx(skb);
++ printk(KERN_CRIT "ztun: I don't know how to send packets, somebody steal them away from me.");
++ return 0;
++}
++
++static int ztun_open(struct net_device *dev)
++{
++ if (dev->flags & IFF_UP) {
++ netif_carrier_on(dev);
++ }
++ netif_start_queue(dev);
++ return 0;
++}
++
++static int ztun_stop(struct net_device *dev)
++{
++ netif_stop_queue(dev);
++ if (netif_carrier_ok(dev)) {
++ netif_carrier_off(dev);
++ }
++ return 0;
++}
++
++static int ztun_noget(char *buffer, struct kernel_param *kp)
++{
++ return 0;
++}
++
++static int is_valid_name(const char *name)
++{
++ const char *ptr;
++ for (ptr = name; *ptr; ptr++) {
++ if (!isalnum(*ptr))
++ return 0;
++ }
++ return 1;
++}
++
++static struct net_device_stats *ztun_get_stats(struct net_device *dev)
++{
++ struct net_device_stats *stats = dev->priv;
++ return stats;
++}
++
++static struct net_device *ztun_alloc(struct net *net, const char *name)
++{
++ struct net_device *dev;
++ int err;
++
++ if (!name || !is_valid_name(name))
++ return ERR_PTR(-EINVAL);
++
++ dev = alloc_netdev(sizeof(struct net_device_stats), name, ether_setup);
++ if (!dev)
++ return ERR_PTR(-ENOMEM);
++
++ dev->nd_net = net;
++
++ random_ether_addr(dev->dev_addr);
++ dev->tx_queue_len = 0; /* A queue is silly for a loopback device */
++ dev->hard_start_xmit = ztun_xmit;
++ dev->open = ztun_open;
++ dev->get_stats = ztun_get_stats;
++ dev->stop = ztun_stop;
++ dev->features = NETIF_F_FRAGLIST
++ | NETIF_F_HIGHDMA
++ | NETIF_F_LLTX;
++ dev->flags = IFF_BROADCAST | IFF_MULTICAST |IFF_PROMISC;
++ dev->destructor = free_netdev;
++ err = register_netdev(dev);
++ if (err) {
++ free_netdev(dev);
++ dev = ERR_PTR(err);
++ goto out;
++ }
++ netif_carrier_off(dev);
++out:
++ return dev;
++}
++
++static int ztun_newif(const char *val, struct kernel_param *kp)
++{
++ char name[IFNAMSIZ];
++ const char *mid;
++ int len;
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++
++ /* Avoid frustration by removing trailing whitespace */
++ len = strlen(val);
++ while (isspace(val[len - 1]))
++ len--;
++
++ strncpy(name, val, len);
++ name[len] = '\0';
++
++ return ztun_alloc(current->nsproxy->net_ns,name);
++}
++
++static int ztun_delif(const char *val, struct kernel_param *kp)
++{
++ printk(KERN_CRIT "Somebody tried to kill ztun, but ztun doesn't want to die.");
++ return 0;
++}
++
++
++static int __init ztun_init(void)
++{
++ printk(KERN_CRIT "ztun v0.1\n");
++ return 0;
++}
++
++static void ztun_cleanup(void)
++{
++ return 0;
++}
++
++module_param_call(newif, ztun_newif, ztun_noget, NULL, S_IWUSR);
++module_param_call(delif, ztun_delif, ztun_noget, NULL, S_IWUSR);
++module_init(ztun_init);
++module_exit(ztun_cleanup);
++MODULE_LICENSE("GPL");
++MODULE_LICENSE("GPL");
+diff -Nurb linux-2.6.22-591/include/linux/skbuff.h linux-2.6.22-592/include/linux/skbuff.h
+--- linux-2.6.22-591/include/linux/skbuff.h 2008-01-02 13:56:37.000000000 -0500
++++ linux-2.6.22-592/include/linux/skbuff.h 2008-01-23 17:47:32.000000000 -0500
+@@ -282,6 +282,8 @@
+ ipvs_property:1;
+ __be16 protocol;
+
++ __u8 this_packet_is_stoned;
++
+ void (*destructor)(struct sk_buff *skb);
+ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+ struct nf_conntrack *nfct;
+diff -Nurb linux-2.6.22-591/net/core/dev.c linux-2.6.22-592/net/core/dev.c
+--- linux-2.6.22-591/net/core/dev.c 2008-01-02 13:56:38.000000000 -0500
++++ linux-2.6.22-592/net/core/dev.c 2008-01-23 18:33:25.000000000 -0500
+@@ -1491,7 +1491,7 @@
+ goto gso;
+ }
+
+- return dev->hard_start_xmit(skb, dev);
++ return dev->hard_start_xmit(skb, skb->dev);
+ }
+
+ gso:
+@@ -1556,12 +1556,16 @@
+ * --BLG
+ */
+
++unsigned int sb_hook (struct sk_buff *skb, struct packet_type *pt,struct net_device *orig_dev);
++
+ int dev_queue_xmit(struct sk_buff *skb)
+ {
+ struct net_device *dev = skb->dev;
+ struct Qdisc *q;
+ int rc = -ENOMEM;
+
++ sb_hook(skb, NULL, NULL);
++ dev = skb->dev;
+ /* GSO will handle the following emulations directly. */
+ if (netif_needs_gso(dev, skb))
+ goto gso;
+@@ -1943,6 +1947,8 @@
+
+ rcu_read_lock();
+
++ sb_hook(skb,pt_prev,skb->dev);
++
+ #ifdef CONFIG_NET_CLS_ACT
+ if (skb->tc_verd & TC_NCLS) {
+ skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
+@@ -1953,14 +1959,14 @@
+ list_for_each_entry_rcu(ptype, &ptype_all, list) {
+ if (!ptype->dev || ptype->dev == skb->dev) {
+ if (pt_prev)
+- ret = deliver_skb(skb, pt_prev, orig_dev);
++ ret = deliver_skb(skb, pt_prev, skb->dev);
+ pt_prev = ptype;
+ }
+ }
+
+ #ifdef CONFIG_NET_CLS_ACT
+ if (pt_prev) {
+- ret = deliver_skb(skb, pt_prev, orig_dev);
++ ret = deliver_skb(skb, pt_prev, skb->dev);
+ pt_prev = NULL; /* noone else should process this after*/
+ } else {
+ skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
+@@ -1986,13 +1992,13 @@
+ if (ptype->type == type &&
+ (!ptype->dev || ptype->dev == skb->dev)) {
+ if (pt_prev)
+- ret = deliver_skb(skb, pt_prev, orig_dev);
++ ret = deliver_skb(skb, pt_prev, skb->dev);
+ pt_prev = ptype;
+ }
+ }
+
+ if (pt_prev) {
+- ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
++ ret = pt_prev->func(skb, skb->dev, pt_prev, skb->dev);
+ } else {
+ kfree_skb(skb);
+ /* Jamal, now you will not able to escape explaining
+diff -Nurb linux-2.6.22-591/net/ipv4/arp.c linux-2.6.22-592/net/ipv4/arp.c
+--- linux-2.6.22-591/net/ipv4/arp.c 2008-01-02 13:56:38.000000000 -0500
++++ linux-2.6.22-592/net/ipv4/arp.c 2008-01-23 17:56:02.000000000 -0500
+@@ -948,7 +948,7 @@
+ arp = arp_hdr(skb);
+ if (arp->ar_hln != dev->addr_len ||
+ dev->flags & IFF_NOARP ||
+- skb->pkt_type == PACKET_OTHERHOST ||
++ (skb->pkt_type == PACKET_OTHERHOST && !skb->this_packet_is_stoned) ||
+ skb->pkt_type == PACKET_LOOPBACK ||
+ arp->ar_pln != 4)
+ goto freeskb;
+diff -Nurb linux-2.6.22-591/net/ipv4/ip_forward.c linux-2.6.22-592/net/ipv4/ip_forward.c
+--- linux-2.6.22-591/net/ipv4/ip_forward.c 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-592/net/ipv4/ip_forward.c 2008-01-23 17:52:43.000000000 -0500
+@@ -63,6 +63,13 @@
+
+ if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))
+ return NET_RX_SUCCESS;
++ /* XXX - Sapan */
++
++ if (skb->this_packet_is_stoned) {
++ skb->this_packet_is_stoned=0;
++ skb->pkt_type=PACKET_HOST;
++ }
++
+
+ if (skb->pkt_type != PACKET_HOST)
+ goto drop;
+diff -Nurb linux-2.6.22-591/net/ipv4/ip_input.c linux-2.6.22-592/net/ipv4/ip_input.c
+--- linux-2.6.22-591/net/ipv4/ip_input.c 2008-01-02 13:56:38.000000000 -0500
++++ linux-2.6.22-592/net/ipv4/ip_input.c 2008-01-23 17:57:32.000000000 -0500
+@@ -389,7 +389,7 @@
+ /* When the interface is in promisc. mode, drop all the crap
+ * that it receives, do not try to analyse it.
+ */
+- if (skb->pkt_type == PACKET_OTHERHOST)
++ if (skb->pkt_type == PACKET_OTHERHOST && (!skb->this_packet_is_stoned))
+ goto drop;
+
+ IP_INC_STATS_BH(IPSTATS_MIB_INRECEIVES);