From 198fadffc522912496c1e4f51768b7e9a8feac37 Mon Sep 17 00:00:00 2001
From: Sapan Bhatia <sapanb@cs.princeton.edu>
Date: Thu, 24 Jan 2008 00:15:16 +0000
Subject: [PATCH]

---
 kernel-2.6-planetlab.spec   |   2 +
 linux-2.6-592-ztun-sb.patch | 562 ++++++++++++++++++++++++++++++++++++
 2 files changed, 564 insertions(+)
 create mode 100644 linux-2.6-592-ztun-sb.patch

diff --git a/kernel-2.6-planetlab.spec b/kernel-2.6-planetlab.spec
index e73224d69..f2db8db39 100644
--- a/kernel-2.6-planetlab.spec
+++ b/kernel-2.6-planetlab.spec
@@ -153,6 +153,7 @@ Patch560: linux-2.6-560-mmconf.patch
 Patch570: linux-2.6-570-tagxid.patch
 Patch590: linux-2.6-590-trellis-mm1-netns.patch
 Patch591: linux-2.6-591-unshare-netns.patch
+Patch592: linux-2.6-592-ztun-sb.patch
 
 %description
 The kernel package contains the Linux kernel (vmlinuz), the core of any
@@ -328,6 +329,7 @@ KERNEL_PREVIOUS=vanilla
 %if 0%{?_with_netns}
 %ApplyPatch 590
 %ApplyPatch 591
+%ApplyPatch 592
 %endif
 
 # NetNS conflict-resolving patch for VINI. Will work with patch vini_pl_patch-1 but may
diff --git a/linux-2.6-592-ztun-sb.patch b/linux-2.6-592-ztun-sb.patch
new file mode 100644
index 000000000..1433d6f68
--- /dev/null
+++ b/linux-2.6-592-ztun-sb.patch
@@ -0,0 +1,562 @@
+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);
-- 
2.47.0