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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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 %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 "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* 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);