/*
 *	Definitions for the 'sk_buff' memory handlers.
 *
 *	Authors:
 *		Alan Cox, <gw4pts@gw4pts.ampr.org>
 *		Florian La Roche, <rzsfl@rz.uni-sb.de>
 *
 *	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.
 */
 
#ifndef _LINUX_SKBUFF_H
#define _LINUX_SKBUFF_H
#include <linux/malloc.h>
#include <linux/wait.h>
#include <linux/time.h>

#define CONFIG_SKB_CHECK	1

#define HAVE_ALLOC_SKB		/* For the drivers to know */


#define FREE_READ	1
#define FREE_WRITE	0

typedef struct __sk_buff sk_buff;

typedef struct {
  sk_buff		* volatile next;
  sk_buff		* volatile prev;
#if CONFIG_SKB_CHECK
  int				magic_debug_cookie;
#endif
} sk_buff_head;


struct __sk_buff 
{

	/* List management section: Must match skb_buff_head */

	sk_buff			* volatile next;
	sk_buff			* volatile prev;
#if CONFIG_SKB_CHECK
	int			magic_debug_cookie;
#endif

	sk_buff			* volatile link3;
  
  	/* Buffer management section */
  
	unsigned char 		* start;	/* Start of data memory */
	unsigned char		* end;		/* End of data memory   */
	unsigned char		* head;		/* Start of actual data */
	unsigned char		* tail;		/* End of actual data   */
	unsigned long 		len;		/* Length of data 	*/
	unsigned long		mem_len;	/* Memory length of buffer */
  
	
	/* General socket tags and resources */
	
	struct sock		*sk;	/* Owner socket 		*/
	volatile unsigned long	when;	/* Used to compute rtt's	*/
	struct timeval		stamp;	/* Packet delivery stamp	*/
	struct device		*dev;	/* Owner device			*/

	/* Scheduled for redesign */
	
	union {
		struct tcphdr		*th;
		struct ethhdr		*eth;
		struct iphdr		*iph;
		struct udphdr		*uh;
		unsigned char		*raw;
		unsigned long		seq;
	} h;
	
	struct iphdr			*ip_hdr;		/* For IPPROTO_RAW */
	struct tcphdr			*thptr;			/* For IPPROTO_TCP retransmisisons */
	unsigned long 			saddr;			/* For IP control layers */
	unsigned long 			daddr;
	unsigned long			raddr;			/* For ARP */
	struct protocol			*protocol;		/* For ARP and for deferring */
	void 				*tag_saddr,*tag_daddr;	/* For deferring */
	void				*lower_head;		/* Lower layer header pointer */
	struct protocol			*tag_lower;		/* Lower protocol on defer */
	unsigned char			deferred;		/* SKB has been deferred */
	
	/* Flags and control */
	
	volatile char	 		acked,
					used,
					free;
	unsigned char			tries,lock,localroute,pkt_type,priority;

#define PACKET_HOST		0		/* To us */
#define PACKET_BROADCAST	1
#define PACKET_MULTICAST	2
#define PACKET_OTHERHOST	3		/* Unmatched promiscuous */
	unsigned short			users;		/* User count - see datagram.c (and soon seqpacket.c/stream.c) */
#ifdef CONFIG_SLAVE_BALANCING
	unsigned short			in_dev_queue;
#endif  
	int				protnum;	/* Protocol classification */
};

#define SK_WMEM_MAX	32767
#define SK_RMEM_MAX	32767

#ifdef CONFIG_SKB_CHECK
#define SK_FREED_SKB	0x0DE2C0DE
#define SK_GOOD_SKB	0xDEC0DED1
#define SK_HEAD_SKB	0x12231298
#endif

#ifdef __KERNEL__
/*
 *	Handling routines are only of interest to the kernel
 */
 
#if 0
extern void			print_skb(sk_buff *);
#endif
extern void			kfree_skb(sk_buff *skb, int rw);
extern void			skb_queue_head_init(sk_buff_head *list);
extern void			skb_queue_head(sk_buff_head *list,sk_buff *buf);
extern void			skb_queue_tail(sk_buff_head *list,sk_buff *buf);
extern sk_buff *		skb_dequeue(sk_buff_head *list);
extern void 			skb_insert(sk_buff *old,sk_buff *newsk);
extern void			skb_append(sk_buff *old,sk_buff *newsk);
extern void			skb_unlink(sk_buff *buf);
extern sk_buff *		skb_peek_copy(sk_buff_head *list);
extern sk_buff *		alloc_skb(unsigned int size, int priority);
extern void			kfree_skbmem(sk_buff *skb, unsigned size);
extern sk_buff *		skb_clone(sk_buff *skb, int priority);
extern void			skb_device_lock(sk_buff *skb);
extern void			skb_device_unlock(sk_buff *skb);
extern void			dev_kfree_skb(sk_buff *skb, int mode);
extern int			skb_device_locked(sk_buff *skb);
extern sk_buff *		dev_alloc_skb(int size);
extern void 			skb_trim(sk_buff *, int);
extern unsigned char *		skb_push(sk_buff *skb, int len);
extern unsigned char *		skb_put(sk_buff *skb, int len);
extern unsigned char *		skb_pull(sk_buff *skb, int len, int *size);
extern unsigned char *		skb_data(sk_buff *skb);
extern int 			skb_reserve(sk_buff *skb, int len);

/*
 *	Peek an sk_buff. Unlike most other operations you _MUST_
 *	be careful with this one. A peek leaves the buffer on the
 *	list and someone else may run off with it. For an interrupt
 *	type system cli() peek the buffer copy the data and sti();
 */
static __inline__ sk_buff *skb_peek(sk_buff_head *list_)
{
	sk_buff *list = (sk_buff *)list_;
	return (list->next != list)? list->next : NULL;
}

#if CONFIG_SKB_CHECK
extern int 			skb_check(sk_buff *skb,int,int, char *);
#define IS_SKB(skb)		skb_check((skb), 0, __LINE__,__FILE__)
#define IS_SKB_HEAD(skb)	skb_check((skb), 1, __LINE__,__FILE__)
#else
#define IS_SKB(skb)		0
#define IS_SKB_HEAD(skb)	0
#endif

extern sk_buff *		skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
extern int			datagram_select(struct sock *sk, int sel_type, select_table *wait);
extern void			skb_copy_datagram(sk_buff *from, int offset, char *to,int size);
extern void			skb_copy_datagram_iovec(sk_buff *from, int offset, struct iovec *to, int size);
extern void			skb_free_datagram(sk_buff *skb);

#endif	/* __KERNEL__ */
#endif	/* _LINUX_SKBUFF_H */
