/*
 *	NET3:	Implementation of protocol layer support routines.
 *	
 *		Alan Cox, <A.Cox@swansea.ac.uk / gw4pts@gw4pts.ampr.org>
 *
 *	The net_bh handler is based on code from Ross Biro. The demultiplexor is
 *	partially based on the ideas in the IP demultiplexor by Ross Biro & 
 *	Fred. N. Van Kempen.
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License
 *	as published by the Free Software Foundation; either version
 *	2 of the License, or (at your option) any later version.
 */

#include <asm/segment.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/netprotocol.h>
#include <linux/netdevice.h>

/*#define PROTO_LAYER_DEBUG*/

/*
 *	Maximum number of backlog frames we will queue at any time. This controls memory allocation
 *	and avoids bursts of ultra heavy traffic causing excessive memory thrashing.
 */
 
#define MAX_LOOPBACK_QUEUE_SIZE		256

/*
 *	We get into some fairly hairy data structures here. The basic idea is that each protocol layer has a protocol
 *	structure bound to an arbitary number of other protocol structures with bindings. Each binding may be multiple
 *	usage and if so is only finally deleted the last use.
 *	In addition the bindings are hooked into a hashed list of upcalls for each layer so that protocol demultiplexing
 *	is both generic and easy.
 *
 *	Practical upshot:
 *		I hope you are good with pointers ;)
 *
 */
 

/*
 *	Manipulators for the protocol binding list.
 *
 *	Assumptions:
 *		You never pass an invalid pointer.
 *		You never unhook something not hooked.
 *		No fiddling during interrupts (currently) - FIXME
 */
 
/*
 *	Undo a lower binding. This entails finding the binding matching the key/keysize we have been given
 *	and reducing its usage count. If it hits zero we delete the entry. Someone else worries about the
 *	demultiplexor hashing.
 */
 
void protocol_unhook_lower(struct protocol *us, struct protocol *lower, unsigned char *key, int keylen)
{
	unsigned long flags;
	struct binding *p=us->lower;
	
	save_flags(flags);
	cli();
	
	if(us->lower!=NULL && p->owner==lower && memcmp(p->key,key,keylen)==0)
	{
		if(!--p->usage)
		{
			us->lower=p->next;
			kfree_s(p,sizeof(*p));
		}
		restore_flags(flags);
		return;
	}
	while(p->next!=NULL)
	{
		if(p->next->owner==lower && memcmp(p->next->key, key, keylen)==0)
		{
			if(!--p->next->usage)
			{
				struct binding *t=p->next;
				p->next=t->next;
				kfree_s(t,sizeof(*t));
			}
			restore_flags(flags);
			return;
		}
		p=p->next;
	}
#ifdef PROTO_LAYER_DEBUG	
	printk("protocol_unhook_lower: protocol not found.\n");
#endif	
	restore_flags(flags);
}

/*
 *	Add a lower layer hook. If an entry already exists just up its usage count.
 */

struct binding *protocol_hook_lower(struct protocol *us, struct protocol *lower, unsigned char *key, int keysize)
{
	struct binding *b;
	unsigned long flags;
	
	save_flags(flags);
	cli();
	for(b=us->lower;b!=NULL;b=b->next)
	{
		if(b->owner==lower && memcmp(b->key, key, b->keysize)==0)
		{
			b->usage++;
			restore_flags(flags);
			return b;
		}
	}
	b=kmalloc(sizeof(*b), GFP_ATOMIC);
	if(b==NULL)
	{
		restore_flags(flags);
		return NULL;
	}
	b->usage=1;
	b->owner=lower;
	b->next=us->lower;
	b->copying=0;
	b->keysize=keysize;
	memcpy(b->key,key,keysize);
	us->lower=b;
	restore_flags(flags);
	return b;
}

/*
 *	Undo an upper binding. This entails finding the binding matching the key/keysize we have been given
 *	and reducing its usage count. If it hits zero we delete the entry. Someone else worries about the
 *	demultiplexor hashing.
 */

void protocol_unhook_upper(struct protocol *us, struct protocol *upper, unsigned char *key, int keylen)
{
	struct binding *p=us->upper;
	unsigned long flags;
	
	save_flags(flags);
	cli();
	
	if(us->upper!=NULL && p->owner==upper && memcmp(p->key,key,keylen)==0 )
	{
		if(!--p->usage)
		{
			us->upper=p->next;
			kfree_s(p,sizeof(*p));
		}
		restore_flags(flags);
		return;
	}
	while(p->next!=NULL)
	{
		if(p->next->owner==upper && memcmp(p->next->key, key, keylen)==0)
		{
			if(!--p->next->usage)
			{
				struct binding *t=p->next;
				p->next=t->next;
				kfree_s(t,sizeof(*t));
			}
			restore_flags(flags);
			return;
		}
		p=p->next;
	}
#ifdef PROTO_LAYER_DEBUG	
	printk("protocol_unhook_upper: protocol not found.\n");
#endif	
	restore_flags(flags);
}

/*
 *	Add an upper layer hook. If an entry already exists just up its usage count.
 */

struct binding *protocol_hook_upper(struct protocol *us, struct protocol *upper, unsigned char *key, int keysize)
{
	struct binding *b;
	unsigned long flags;
	
	save_flags(flags);
	cli();
	for(b=us->upper;b!=NULL;b=b->next)
	{
		if(b->owner==upper && memcmp(b->key, key, b->keysize)==0)
		{
			b->usage++;
			restore_flags(flags);
			return b;
		}
	}
	b=kmalloc(sizeof(*b), GFP_ATOMIC);
	if(b==NULL)
		return NULL;
	b->usage=1;
	b->owner=upper;
	b->next=us->upper;
	b->keysize=keysize;
	memcpy(b->key,key,keysize);
	us->upper=b;
	restore_flags(flags);
	return b;
}


/*
 *	Master protocol list handlers. This is fairly simple. It allows us to find a protocol
 *	by its declared name.
 */
 
static struct protocol *protocols=NULL;

/*
 *	Simple add
 */
 
void protocol_register(struct protocol *proto)
{
	unsigned long flags;
	save_flags(flags);
	cli();
	proto->next=protocols;
	protocols=proto;
	restore_flags(flags);
}

/*
 *	Remove a protocol. Refuse to remove it if it has bindings.
 */

int protocol_unregister(struct protocol *proto)
{
	struct protocol *p=protocols;
	unsigned long flags;
	
	save_flags(flags);
	cli();
	
	if(proto->lower || proto->upper)
	{
		restore_flags(flags);
		return -EBUSY;
	}
	
	if(protocols==proto)
	{
		protocols=proto->next;
		restore_flags(flags);
		return 0;
	}
	while(p->next!=NULL)
	{
		if(p->next==proto)
		{
			p->next=proto->next;
			restore_flags(flags);
			return 0;
		}
		p=p->next;
	}
	restore_flags(flags);
	return -ESRCH;
}

/*
 *	Find the protocol pointer from the name.
 */

struct protocol *protocol_find(char *name)
{
	struct protocol *p=protocols;
	while(p!=NULL)
	{
		if(strcmp(p->name,name)==0 && p->device==NULL)
			return p;
		p=p->next;
	}
	return NULL;
}

/*
 *	Find a protocol instance attached to a device.
 */
 
struct protocol *protocol_find_instance(char *name, struct device *dev)
{
	struct protocol *p=protocols;
	while(p!=NULL)
	{
		if(strcmp(p->name,name)==0 && p->device==dev)
			return p;
		p=p->next;
	}
	return NULL;
}

/*
 *	Make a copy of a protocol.
 */
 
struct protocol *protocol_clone_keep(struct protocol *us)
{
	struct protocol *n=kmalloc(sizeof(*n),GFP_ATOMIC);
	if(n==NULL)
		return NULL;
	memcpy(n,us,sizeof(*n));
	n->next=NULL;
	n->lower=NULL;
	n->upper=NULL;
	n->name="CLONE";
	n->flags=0;
	protocol_register(n);
	return n;
}

struct protocol *protocol_clone(struct protocol *us)
{
	struct protocol *n=protocol_clone_keep(us);
	if(n==NULL)
		return NULL;
	n->flags|=PF_TEMP;
	return n;
}

/*
 *	Attempt to discard a protocol
 */
 
static inline void protocol_flush(struct protocol *us)
{
	unsigned long flags;
	save_flags(flags);
	cli();
	if(us->flags&PF_TEMP)
	{
		if(us->lower==NULL && us->upper==NULL)
		{
#ifdef PROTO_LAYER_DEBUG		
			printk("Flushed protocol %s.\n",us->name);
#endif			
			protocol_unregister(us);
			kfree_s((void *)us,sizeof(struct protocol));
		}
	}
	restore_flags(flags);
}


void protocol_delete(struct protocol *us)
{
	us->flags|=PF_TEMP;
	protocol_flush(us);
}

/*
 *	Control message passing functions
 */		
 
static inline int protocol_inform(struct protocol *self, struct protocol *target, int op, void *arg)
{
	if(target->control_event!=NULL)
		return target->control_event(target,self,op,arg);
	else
		return 0;
}

void protocol_inform_lower(struct protocol *self, int op, void *arg)
{
	struct binding *p=self->lower;
	while(p!=NULL)
	{
		protocol_inform(self,p->owner,op,arg);
		p=p->next;
	}
}

void protocol_inform_upper(struct protocol *self, int op, void *arg)
{
	struct binding *p=self->upper;
	while(p!=NULL)
	{
		protocol_inform(self,p->owner,op,arg);
		p=p->next;
	}
}

/*
 *	Head/Tail size control
 */
 
static void lower_ht_sizes(struct protocol *self,int *head,int *tail)
{
	int h=0,t=0;
	struct binding *p=self->lower;
#ifdef PROTO_LAYER_DEBUG
	printk("Scanning lower modules of %s\n",self->name);
#endif	
	while(p!=NULL)
	{
#ifdef PROTOCOL_LAYER_DEBUG	
		printk("[%s %d,%d] ",p->name,p->header_space,p->tail_space);
#endif		
		if(p->owner->header_space>h)
			h=p->owner->header_space;
		if(p->owner->tail_space>t)
			t=p->owner->tail_space;
		p=p->next;
	}
#ifdef PROTO_LAYER_DEBUG	
	printk("\nHead=%d Tail=%d\n",h,t);
#endif	
	*head=h;
	*tail=t;
}

/*
 *	Send the messages to keep the worst case head/tail sizes right.
 */
 
static void protocol_size_resync(struct protocol *upper)
{
	int hs,ts;
	lower_ht_sizes(upper,&hs,&ts);
	if(hs+upper->base_header_space!=upper->header_space)
	{
		upper->header_space=hs+upper->base_header_space;
		protocol_inform_upper(upper,CTL_HEAD_CHANGE_BELOW,&upper->header_space);
	}
	if(ts+upper->base_tail_space!=upper->tail_space)
	{
		upper->tail_space=ts+upper->base_tail_space;
		protocol_inform_upper(upper,CTL_TAIL_CHANGE_BELOW,&upper->tail_space);
	}
}

/*
 *	Protocol layer binding call:
 *	
 *	Binds two protocol units together and propogates the correct messages to
 *	get sizes in synchronization and layers bound. 
 */	

int protocol_bind(struct protocol *lower, struct protocol *upper, int protocol, int subid)
{
	char key[8];
	int keysize;
	struct binding *b;
	unsigned long flags;
	
	/*
	 *	Ask the lower protocol for a key to the upper protocol. If this returns
	 *	an error we cannot bind.
	 */
	
	keysize=lower->get_binding(protocol, subid, key);
	if(keysize<0)
	{
#ifdef PROTO_LAYER_DEBUG	
		printk("Bind of %s to %s failed.\n", lower->name, upper->name);
#endif		
		return keysize;
	}		
	
	/*
	 *	Well why fuss about hashing zero length keys? We sort of handwave a 0
	 *	into the key for the hash function. If it offends your sense of 
	 *	pure clean algorithms then do something useful like calculating the
	 *	order and performance of the alternatives ;)
	 */
	
	if(keysize==0)
		key[0]=0;
		
	/*
	 *	Join the two entries together
	 */
	 
	if(protocol_hook_lower(upper,lower, key, keysize)==NULL)
		return -ENOMEM;
	save_flags(flags);
	cli();
	if((b=protocol_hook_upper(lower,upper, key, keysize))==NULL)
	{
		protocol_unhook_lower(upper,lower, key, keysize);
		restore_flags(flags);
		return -ENOMEM;
	}
	/*
	 *	If we are new then multiplex us.
	 */
	if(b->usage==1)
		protocol_demultiplex_add(lower, b);
	/* lower tells upper it is bound */
	protocol_inform(lower,upper,CTL_BOUND_BELOW,lower);
	/* upper tells lower it is bound */
	protocol_inform(upper,lower,CTL_BOUND_ABOVE,upper);
	/* Sort sizes out */
	protocol_size_resync(upper);
	restore_flags(flags);
	return 0;
}

/*
 *	Protocol layer unbinding call:
 *
 *	Unbinds two protocol units. Since this may reduce the head and tail space
 *	for the protocol layer the sizes of the upper module are recalculated and
 *	resynchronized.
 *
 *	MUST NEVER BE CALLED FROM AN INTERRUPT OR NET_BH HANDLER. (YES I KNOW IP DOES IT
 *	BUT THAT NEEDS FIXING!)
 */
 
void protocol_unbind(struct protocol *lower, struct protocol *upper, int protocol, int subid)
{
	char key[8];
	int keysize;
	unsigned long flags;

	/*
	 *	Ask the lower protocol for a key to the upper protocol. If this returns
	 *	an error we cannot bind.
	 */
	
	keysize=lower->get_binding(protocol,subid, key);
	if(keysize<0)
		return;
		
	/*
	 *	It's easier to quietly ignore the 0 length key hash issue like this
	 */
	 
	if(keysize==0)
		*key=0;

	/*
	 *	Remove the multiplexor entry (if needed)
	 */
	 
	protocol_demultiplex_remove(lower, upper, key, keysize);
	
	/*
	 *	Disconnect the layers
	 */
	 
	protocol_unhook_lower(upper,lower, key, keysize);
	protocol_unhook_upper(lower,upper, key, keysize);
	
	/*
	 *	Make sure the layers know what is up.
	 */
	 
	save_flags(flags);
	cli();
	protocol_inform(lower,upper,CTL_DISCONNECT_BELOW,lower);
	protocol_inform(upper, lower, CTL_DISCONNECT_ABOVE, upper);
	
	/*
	 *	Adjust the size (we may have shrunk)
	 */
	 
	protocol_size_resync(upper);
	
	/*
	 *	Discard what we can.
	 */

	restore_flags(flags);
	protocol_flush(upper);
	protocol_flush(lower);
}



/*
 *	Default handler for control events.
 */
 
int default_protocol_control(struct protocol *self, struct protocol *src, int event, void *arg)
{
	struct binding *p;
#ifdef PROTO_LAYER_DEBUG	
	printk("Control event for %s: ",self->name);
#endif	
	switch(event)
	{
		case CTL_BOUND_BELOW:
#ifdef PROTO_LAYER_DEBUG		
			printk("%s bound below.\n",src->name);
#endif			
			self->stream_down=src;
			return 0;
		case CTL_BOUND_ABOVE:
#ifdef PROTO_LAYER_DEBUG		
			printk("%s bound above.\n",src->name);
#endif			
			self->stream_up=src;
			return 0;
		case CTL_HEAD_CHANGE_BELOW:
#ifdef PROTO_LAYER_DEBUG		
			printk("head changed below to size %d.\n",*((int *)arg));
#endif			
			self->header_space=self->base_header_space+ *((int *)arg);
			for(p=self->upper;p!=NULL;p=p->next)
				protocol_size_resync(p->owner);	/* Get our upper layers right too */
			return 0;
		case CTL_TAIL_CHANGE_BELOW:
#ifdef PROTO_LAYER_DEBUG		
			printk("tail changed below to size %d.\n",*((int *)arg));
#endif			
			self->tail_space=self->base_tail_space+ *((int *)arg);
			for(p=self->upper;p!=NULL;p=p->next)
				protocol_size_resync(p->owner);	/* Get our upper layers right too */
			return 0;
		case CTL_DISCONNECT_BELOW:
#ifdef PROTO_LAYER_DEBUG		
			printk("%s disconnected below.\n",src->name);
#endif			
			if(self->stream_down==src)
				self->stream_down=NULL;
			return 0;
		case CTL_DISCONNECT_ABOVE:
#ifdef PROTO_LAYER_DEBUG		
			printk("%s disconnected above.\n",src->name);
#endif			
			if(self->stream_up==src)
				self->stream_up=NULL;
			return 0;
		default:
#ifdef PROTO_LAYER_DEBUG		
			printk("Unknown event %d from %s.\n",event,src->name);
#endif			
			return -ENOPROTOOPT;
	}
}


/*
 *	Support and utility functions
 */
 
unsigned short protocol_size(struct protocol *p)
{
	return p->header_space+p->tail_space;
}

void protocol_adjust(sk_buff *skb, struct protocol *proto)
{
	skb_reserve(skb,proto->header_space);
}


/*
 *	Generic demultiplexors for byte and word sized lists. The following is
 *	used for both byte and word. The hash is optimised more for _little_endian_
 *	systems. With a big endian host you may wish to use a different method.
 *
 *	This also assumes fixed keysizes. Add demultiplexors as needed. IP already
 *	uses its own for example although IP could use these (and maybe ought to).
 *
 *	The basic aim of this is to hash by the lead byte of the code (adjust and
 *	write protocol specific variants as needed), and to maintain a set of hashed
 *	lists, hopefully only one element long in normal use. If they don't fall out
 *	as one long normally then alter the demultiplexor for that type or in general.
 *
 *	We keep each list such that multiple copies of a protocol entry have the
 *	'copying' flag on all but the last.
 *
 *	We must demultiplex the following lists into single hits to avoid copies
 *	with the current code.
 *
 *	Ethernet:	0x0800(IP)  0x0806(ARP)   0x8137(IPX)		[0x0, 0x3, 0xB]
 *	802.2	:	0xAA(IPX)  0xFF(IPX 802.3)			[0x5, 0xF]
 *	IP	:	0x01(ICMP) 0x04(ENCAP) 0x06(TCP) 0x17(UDP)	[0x0, 0x02, 0x03, 0x0B]
 */
 
static inline int protocol_hash(unsigned char *p)
{
	return((p[0]>>1)&0x0F);
}
 
/*
 *	Add a demultiplexor link. We put ourselves at the start and then search for the first match to us. If we find one
 *	we set our copying flag to 1 so that both will get the data.
 */

void protocol_demultiplex_add(struct protocol *lower,struct binding *self)
{
	struct binding *p;
	int hash=protocol_hash(self->key);

#ifdef PROTO_LAYER_DEBUG	
	printk("%s: Demultiplex add for %s of hash %d\n",lower->name,self->owner->name, hash);
#endif	
	self->copying=0;
	self->next_demul=lower->demultiplex[hash];
	lower->demultiplex[hash]=self;
	for(p=self->next_demul;p!=NULL;p=p->next_demul)
	{
		if(memcmp(self->key,p->key,self->keysize)==0)
		{
			self->copying=1;
			break;
		}
	}
}

/*
 *	Remove a demultiplexor entry. Most of this is for the case of usage=1 - a real removal.
 */
 
void protocol_demultiplex_remove(struct protocol *lower, struct protocol *self, unsigned char *key, int keylen)
{
	int hash=protocol_hash(key);
	struct binding *p=lower->demultiplex[hash];
	struct binding *np=NULL;
	if(p==NULL)
		return;
	if(p->owner==self)
	{
		if(p->usage==1)
		{
			lower->demultiplex[hash]=p->next_demul;
		}
		np=p;
	}
	else
	{
		while(p->next_demul!=NULL)
		{
			np=p->next_demul;
			if(np->owner==self && memcmp(np->key, key, keylen)==0)
			{
				if(np->usage==1)
					p->next_demul=np->next_demul;
				break;
			}
			p=p->next_demul;
		}
	}
	
	/*
	 *	At this point np is the entry we are unhooking. IFF it has copying set and will be removed
	 *	find the new last entry and reset its copying flag.
	 */
	 
	if(np && np->copying && np->usage==1)
	{
		p=NULL;
		for(np=lower->demultiplex[hash];np!=NULL;np=np->next_demul)
		{
			if(memcmp(key,np->key,keylen)==0)
			{
				p=np;
			}
		}
		if(p!=NULL)
			p->copying=0;
		else	/* This can't occur as self->copying would be 0 .. */
			printk("protocol_demultiplex_remove: copy flag error.\n");
	}
}


/*
 *	These may well end up inlined.
 */
 
struct binding *protocol_byte_demultiplex(struct protocol *self, unsigned char *key)
{
	struct binding *p=self->demultiplex[protocol_hash(key)];
	while(p!=NULL)
	{
		if(p->key[0]== *key)
			return p;
		p=p->next_demul;
	}
	return NULL;
}


struct binding *protocol_demultiplex(struct protocol *self, unsigned char *key)
{
	struct binding *p=self->demultiplex[protocol_hash(key)];
#ifdef PROTO_LAYER_DEBUG	
/*	printk("%s: Demultiplex on %02X.%02X ",self->name,(int)key[0],(int)key[1]);*/
#endif	
	while(p!=NULL)
	{
		/* We do this knowing that memcmp is a builtin. If it wasn't we would use
		   a pair of comparisons or a word cast and compare */
		if(memcmp(p->key,key,p->keysize)==0)
		{
#ifdef PROTO_LAYER_DEBUG		
/*			printk("is %s\n",p->owner->name);*/
#endif			
			return p;
		}
		p=p->next_demul;
	}
#ifdef PROTO_LAYER_DEBUG	
/*	printk(" not found.\n");*/
#endif	
	return NULL;
}

struct binding *protocol_byte_next(struct binding *p, unsigned char *key)
{
	p=p->next_demul;
	while(p!=NULL)
	{
		if(p->key[0]== *key)
			return p;
		p=p->next_demul;
	}
	return NULL;
}

struct binding *protocol_next(struct binding *p, unsigned char *key)
{
	p=p->next_demul;
	while(p!=NULL)
	{
		if(memcmp(p->key,key,p->keysize)==0)
			return p;
		p=p->next_demul;
	}
	return NULL;
}

/*
 *	This will eventually be inlined. Its big but too important and speed critical.
 *
 *	Don't be confused by the calls to input/bh_input. self is the person
 *	passing the skb and thus becomes lower on the input. I mention this
 *	because I spent four hours discovering I had this backwards 8)
 */

int protocol_pass_demultiplex(struct protocol *self, void *key, sk_buff *skb, void *saddr, void *daddr)
{
	struct binding *p=protocol_demultiplex(self, key);
	if(!p)
	{
		return 0;
	}
	while(p->copying)
	{
		sk_buff *new=skb_clone(skb,GFP_ATOMIC);
		if(new)
			(skb->deferred?p->owner->bh_input:p->owner->input)(p->owner, self, new,saddr,daddr);
		p=protocol_next(p, key);
	}
	(skb->deferred?p->owner->bh_input:p->owner->input)(p->owner, self, skb,saddr,daddr);
	return 1;
}


/*
 *	Defer a packet to a protocol bottom half handler.
 */

static sk_buff_head backlog = 
{
	(sk_buff *)&backlog, (sk_buff *)&backlog
#ifdef CONFIG_SKB_CHECK
	,SK_HEAD_SKB
#endif
};

/* 
 *	We don't overdo the queue or we will thrash memory badly.
 */
 
static volatile int backlog_size = 0;


/*
 *	Defer an input. Note we don't preserve any optional hints across a defer. They tend to be stacked
 *	so it would be messy to do so.
 */

int protocol_defer(struct protocol *pr, struct protocol *lower, sk_buff *skb, void *saddr, void *daddr)
{
	static int dropping=0;
	skb->protocol=pr;
	skb->tag_saddr=saddr;
	skb->tag_daddr=daddr;
	skb->tag_lower=lower;
	if(skb->deferred)
		printk("protocol_defer: Deferring a deferred packet (Whoops!)\n");
	skb->deferred=1;
	
	/*
	 *	Check that we aren't overdoing things.
	 */

	if(!backlog_size)
  		dropping = 0;
	else if (backlog_size > MAX_LOOPBACK_QUEUE_SIZE)
		dropping = 1;

	if (dropping) 
	{
		kfree_skb(skb, FREE_READ);
		return -1;
	}
	/*
	 *	Add it to the "backlog" queue. 
	 */
	IS_SKB(skb);
	skb_queue_tail(&backlog,skb);
	backlog_size++;
	/*
	 *	Trigger the bottom half handler.
	 */
	mark_bh(NET_BH);
	return 0;
}

/*
 *	This is the new network bottom half handler. It hands off to 'slow' protocol layers (eg tcp). Note that
 *	a layer can do some fast processing and defer 'hard' cases.
 */

volatile char in_bh=0;

void net_bh(void *tmp)
{
	sk_buff *skb;
	unsigned long flags;
	
	save_flags(flags);
	cli();
	if(in_bh==1)
	{
		restore_flags(flags);
		return;
	}
	in_bh=1;
	restore_flags(flags);
	dev_transmit();
	
	cli();
	while((skb=skb_dequeue(&backlog))!=NULL)
	{
		backlog_size--;
		restore_flags(flags);
		skb->protocol->bh_input(skb->protocol,skb->tag_lower,skb,skb->tag_saddr,skb->tag_daddr);
	}
	in_bh=0;
	restore_flags(flags);
	dev_transmit();		/* Flush output */
}
