/*
 * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
 *
 * 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.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free software Foundation, Inc.,
 * 59 Temple Place, suite 330, Boston, MA 02111-1307 USA
 *
 */
#ifndef _VNET_SKB_UTIL_H_
#define _VNET_SKB_UTIL_H_

#ifdef __KERNEL__
#include <net/route.h>
#include <linux/skbuff.h>

#else

#include "skbuff.h"

#endif

struct sk_buff;

extern int skb_make_room(struct sk_buff **pskb, struct sk_buff *skb, int head_n, int tail_n);

extern int skb_put_bits(const struct sk_buff *skb, int offset, void *src, int len);

extern void skb_print_bits(const char *msg, struct sk_buff *skb, int offset, int n);

extern void buf_print(char *buf, int n);

extern void *skb_trim_tail(struct sk_buff *skb, int n);

extern void print_skb_data(const char *msg, int count, struct sk_buff *skb, u8 *data, int len);
extern void print_skb(const char *msg, int count, struct sk_buff *skb);

extern void print_ethhdr(const char *msg, struct sk_buff *skb);
extern void print_iphdr(const char *msg, struct sk_buff *skb);
extern void print_udphdr(const char *msg, struct sk_buff *skb);

/* The mac.ethernet field went away in 2.6 in favour of eth_hdr().
 */
#ifdef __KERNEL__
#  if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#    define NEED_ETH_HDR
#  endif
#else
#  define NEED_ETH_HDR
#endif

#ifdef NEED_ETH_HDR

static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)
{
	return (struct ethhdr *)skb->mac.raw;
}

#endif


#ifdef __KERNEL__

struct scatterlist;

extern int skb_scatterlist(struct sk_buff *skb, struct scatterlist *sg,
                           int *sg_n, int offset, int len);

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)

static inline int skb_route(struct sk_buff *skb, struct rtable **prt){
    int err = 0;
    struct flowi fl = {
        .nl_u = {
            .ip4_u = {
                .daddr = skb->nh.iph->daddr,
                .saddr = skb->nh.iph->saddr,
                .tos   = skb->nh.iph->tos,
            }
        }
    };
    
    if(skb->dev){
        fl.oif = skb->dev->ifindex;
    }
    err = ip_route_output_key(prt, &fl);
    return err;
}

#else

static inline int skb_route(struct sk_buff *skb, struct rtable **prt){
    int err = 0;
    struct rt_key key = { };
    key.dst = skb->nh.iph->daddr;
    key.src = skb->nh.iph->saddr;
    key.tos = skb->nh.iph->tos;
    if(skb->dev){
        key.oif = skb->dev->ifindex;
    }
    err = ip_route_output_key(prt, &key);
    return err;
}

#endif

#endif /* __KERNEL__ */

/** Arp header struct with all the fields so we can access them. */
struct arpheader
{
	unsigned short	ar_hrd;		/* format of hardware address	*/
	unsigned short	ar_pro;		/* format of protocol address	*/
	unsigned char	ar_hln;		/* length of hardware address	*/
	unsigned char	ar_pln;		/* length of protocol address	*/
	unsigned short	ar_op;		/* ARP opcode (command)		*/

#if 1
	 /*
	  *	 Ethernet looks like this : This bit is variable sized however...
	  */
	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address	*/
	unsigned char		ar_sip[4];		/* sender IP address		*/
	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address	*/
	unsigned char		ar_tip[4];		/* target IP address		*/
#endif

};

#endif /* ! _VNET_SKB_UTIL_H_ */
