#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define	 __FAVOR_BSD
#include <netinet/tcp.h>

#define CKSUM_CARRY(x) \
   (x = (x >> 16) + (x & 0xffff), (~(x + (x >> 16)) & 0xffff))

typedef struct tcp_pseudo_header{
  unsigned int   src_addr;
  unsigned int   dst_addr;
  unsigned char  zero;
  unsigned char  proto;
  unsigned short tcp_len;
  char 		 tcp[1500];
}tcp_pseudo_hd_t;


int in_cksum(u_short *addr, int len){
  int sum;
  int nleft;
  u_short ans;
  u_short *w;
  
  sum = 0;
  ans = 0;
  nleft = len;
  w = addr;

  while (nleft > 1){
    sum += *w++;
    nleft -= 2;
  }
  if (nleft == 1){
    *(u_char *)(&ans) = *(u_char *)w;
    sum += ans;
  }
  return (sum);
}

u_int16_t do_tcp_checksum(pack, zero, proto, len, ip_addr)
  u_char        	*pack;  	/* starting from TCP header */
  unsigned char 	zero;		/* the TCP checksum's 'ZERO' field */
  unsigned char 	proto;  	/* IPPROTO_TCP constant */
  unsigned short 	len;		/* (Packet total length) - (IP header length) */
  u_char		*ip_addr;	/* 12 bytes from the beginning of the IP header pointer */
{
  tcp_pseudo_hd_t pseudo_hdr;
  unsigned int sum = 0;
  struct tcphdr *tcp = (struct tcphdr*)(pack);

  memset(&pseudo_hdr,0,sizeof(pseudo_hdr));
  memcpy(&pseudo_hdr.src_addr,ip_addr,4);
  memcpy(&pseudo_hdr.dst_addr,ip_addr+4,4);
  pseudo_hdr.zero       = zero;
  pseudo_hdr.proto      = proto;
  pseudo_hdr.tcp_len    = htons(len);
  memcpy(pseudo_hdr.tcp,tcp,len);
  sum = in_cksum((u_short *)&pseudo_hdr,12+len);
  return CKSUM_CARRY(sum);
}

u_int16_t do_icmp_checksum(u_char *pack,int icmpsize){
  u_int32_t  sum;
  
  sum = in_cksum((u_short*)pack,icmpsize);
  
  sum = (sum >> 16) + (sum & 0xffff);
  sum += (sum >> 16);

  return (u_int16_t)(~sum);

}

