/*
 *	Network Interface Tap.
 *
 *	Authors:	Alan Cox <iialan@iifeak.swan.ac.uk>
 *	
 *	This address family permits you to tap the input or output sides
 *	of a machine. It is different to the older packet behaviour because
 *	mpb.c (multi protocol bridge) needs to be able to tap all receivers
 *	only in a clean manner. It also makes more sense and lets a tap
 *	user tell which is which!
 *
 *	This is mostly built out of the good old gensock routines.
 *
 * 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 <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/config.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/errno.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include "sock.h"
#include "sockgeneric.h"
#include <linux/if_nit.h>

#ifdef CONFIG_NIT

/*
 *	Counters to optimize the nit paths.
 */

int tx_nit_count=0;
int rx_nit_count=0;
int pk_nit_count=0;
struct proto_ops nit_ops;

/*
 *	Things you cannot do with a NIT.
 */
 
static int nitsk_bind(struct socket *sock, struct sockaddr *umyaddr, int sockaddr_len)
{
	return -EINVAL;
}

static int nitsk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock,int flags)
{
	return -EOPNOTSUPP;
}

/*
 *	NIT specific creation rules.
 */
 
static int nitsk_create(struct socket *sock, int protocol)
{
	struct sock *sk;
	struct protocol *tmp;

	if(!suser())
		return -EPERM;
#if 0		
	if(protocol!=NIT_PROTO_RX && protocol!=NIT_PROTO_TX)
		return -EPROTONOSUPPORT;
#endif	
	if(gs_create(sock, protocol)==-1)
		return -EINVAL;

	sk=sock->protocol;
	sk->opt.generic.family=AF_NIT;
	
	/*
	 *	Now attach ourselves.
	 */
	 
	/*
	 *	Plug in generic socket protocol layer 
	 */

	tmp=protocol_clone(&proto_generic);	/* This will default to self destruct when we unbind */
	
	if(tmp==NULL)
	{
		kfree_s(sock->protocol,sizeof(struct sock));
		sock->protocol=NULL;
		return -ENOBUFS;
	}
	
	tmp->user=(void *)sk;
	sk->opt.generic.protocol=tmp;
	
	if(protocol==NIT_PROTO_TX)
	{
		tx_nit_count++;
		protocol_bind(&transmit_protocol,tmp, 0, 0);
	}
	else if(protocol==NIT_PROTO_RX)
	{
		rx_nit_count++;
		protocol_bind(&receive_protocol,tmp, 0,0);
	}
	else
	{
		pk_nit_count++;
		protocol_bind(&packet_protocol,tmp, AF_UNSPEC, sk->num);
	}
	sk->state=TCP_ESTABLISHED;
	return 0;
}


/*
 *	Release a socket. Unbind the link which will free the
 *	cloned gensocket protocol layer, then let the generic
 *	socket releaser do its work.
 */
 
static int nitsk_release(struct socket *sock, struct socket *peer)
{
	struct sock *sk=sock->protocol;
	struct protocol *tmp=sk->opt.generic.protocol;
	if(sk->num==NIT_PROTO_TX)
	{
		tx_nit_count--;
		protocol_unbind(&transmit_protocol, tmp, 0, 0);
	}
	else if(sk->num==NIT_PROTO_RX)
	{
		rx_nit_count--;
		protocol_unbind(&receive_protocol, tmp, 0, 0);
	}
	else
	{
		pk_nit_count--;
		protocol_unbind(&packet_protocol, tmp, AF_UNSPEC, sk->num);
	}
	return gs_release(sock,peer);
}
	
	
void nit_init(void)
{
	printk("NET3 NIT sockets v001\n");
	sock_register(nit_ops.family,&nit_ops);
}

/*
 *	We support three network interface taps. An output tap and two input taps. This
 *	will be a streams driver once I have the streams code sussed. The third tap is
 *	a back compatibility/usefulness item for emulating SOCK_PACKET from 1.0 and 1.2
 */
 
 
/*
 *	Basically a vanilla demultiplexor. Take every frame and throw it at anyone who is interested.
 *	Note that because of the way we obtrusively tap we keep counters to avoid passing data here
 *	if there is nobody interested.
 */
 
static int tap_input(struct protocol *self, struct protocol *below, sk_buff *skb, void *saddr, void *daddr)
{
	if(protocol_pass_demultiplex(self, NULL, skb, saddr, daddr))
		kfree_skb(skb, FREE_READ);
	return 0;
}

static int rx_tap_input(struct protocol *self, struct protocol *below, sk_buff *skb, void *saddr, void *daddr)
{
	if(protocol_pass_demultiplex(self, &skb->protnum, skb, saddr, daddr))
		kfree_skb(skb, FREE_READ);
	return 0;
}
 
 
static int no_key(int proto, int subid, unsigned char *key)
{
	return 0;
}

static int tap_key(int proto, int subid, unsigned char *key)
{
	memcpy(key, &subid,sizeof(subid));
	return sizeof(subid);
}


struct protocol transmit_protocol =
{
	NULL,
	"Transmit Tap",
	0,
	0,
	0,
	0,
	NULL,
	tap_input,
	tap_input,
	default_protocol_control,
	no_key,
};

struct protocol receive_protocol =
{
	NULL,
	"Receive Tap",
	0,
	0,
	0,
	0,
	NULL,		/* You can't output to a tap */
	tap_input,
	tap_input,
	default_protocol_control,
	no_key,
};

struct protocol packet_protocol =
{
	NULL,
	"Packet Tap",
	0,
	0,
	0,
	0,
	NULL,		/* You can't output to a tap */
	rx_tap_input,
	rx_tap_input,
	default_protocol_control,
	tap_key,
};

struct proto_ops nit_ops=
{
	AF_NIT,
	nitsk_create,
	gs_dup,
	nitsk_release,
	nitsk_bind,	/* Not allowed */
	gs_connect,	/* Ditto */
	gs_socketpair,
	gs_accept,
	gs_getname,
	gs_select,
	gs_ioctl,
	gs_listen,
	gs_shutdown,
	gs_setsockopt,
	gs_getsockopt,
	gs_fcntl,
	nitsk_sendmsg,
	gs_recvmsg
};

#endif /* CONFIG_NIT */
