/* Vypocetni rutiny pro CRC ve vsech vrstvach Ethernet modulu */

#include "stdint.h"
#include "net_checksum.h"

/* --------------------------------------------------------------
 Vypocita CRC
 ------------------------------------------------------------- */
// The Ip checksum is calculated over the ip header only starting
// with the header length field and a total length of 20 bytes
// unitl ip.dst
// You must set the IP checksum field to zero before you start
// the calculation.
// len for ip is 20.
//
// For TCP we do not make up the required pseudo header. Instead we 
// use the ip.src and ip.dst fields of the real packet:
// The udp checksum calculation starts with the ip.src field
// Ip.src=4bytes,Ip.dst=4 bytes,Udp header=8bytes + data length=16+len
// In other words the len here is 8 + length over which you actually
// want to calculate the checksum.
// You must set the checksum field to zero before you start
// the calculation.
// len for tcp is: 4+4 + 20 + option len + data length
//
// For more information on how this algorithm works see:
// http://www.netfor2.com/checksum.html
// http://www.msc.uky.edu/ken/cs471/notes/chap3.htm
// The RFC has also a C code example: http://www.faqs.org/rfcs/rfc1071.html
unsigned int NET_checksum(unsigned char *buf, unsigned  int len, unsigned char type)
{
	// len ... pres kolik byte se ma check sum pocitat
	//		IP checksum .....
	//		TCP checksum .... Paket bez dat a bez Option casti -> len = 28
	//						  Paket bez dat s Option casti     -> len = 28+4+22
	//						  Paket s daty a bez Option csti   -> len = 28+DataLen
	// type = 0...ip, 1...udp, 2...tcp
	// Pred zavolanim funkce se musi vynulovat obsach bytu v bufferu odesilaneho paketu
	// odpovidajicich poloze pocitaneho check sumu, protoze se check sum pocita i pres tyto byty !!!
	unsigned long sum = 0;		// Pocatecni vynulovani CheckSumu
	
	if (type==TCP_TYPE)							// Korekce na pseudo hlavicku aby checksum vysel spravne
	{
		sum+=6;
		sum+=len-8; 
	}
	else if (type==UDP_TYPE)					// Korekce na pseudo hlavicku aby checksum vysel spravne
	{
		sum+=17;
		sum+=len-8; 
	}
	// build the sum of 16bit words
	while(len >1)
	{
		sum += 0xFFFF & (*buf<<8|*(buf+1));
		buf+=2;
		len-=2;
	}
	// if there is a byte left then add it (padded with zero)
	if (len)
	{
		sum += (0xFF & *buf)<<8;
	}
	// now calculate the sum over the bytes in the sum
	// until the result is only 16bit long
	while (sum>>16)
	{
		sum = (sum & 0xFFFF)+(sum >> 16);
	}
	// build 1's complement:
	return( (unsigned  int) sum ^ 0xFFFF);
}


/* Konec souboru */
