IP和TCP包頭校驗和計算方法
校驗和的算法:
將數據以字爲單位累加到一個雙字中,如果數據長度爲奇數,最後一個字節要先變成字,然後在加到原來的雙字中,最後得到的結果是一個雙字,最後將這個雙字的高16位和低16位反覆相加,直到高16位爲0,從而就獲得一個16位的值,再將這個16位的值取反就得到校驗和的值了。
在接收端接收到IP數據包後,要對IP頭進行檢查看是否有誤,所用的算法與上面一致,不同的是最終的結果要爲0。
程序如下:
USHORT checksum(USHORT* buffer, int size){
unsigned long cksum=0;
while(size>1){
cksum =*buffer ;
size-=sizeof(USHORT);
}
if(size){
cksum =*(UCHAR*)buffer;
}
cksum=(cksum>>16) (cksum&0xffff);
cksum =(cksum>>16);
return (USHORT)(~cksum);
}
實例:
IP頭:
45 00 00 31
89 F5 00 00
6E 06 00 00(校驗字段)
DE B7 45 5D -> 222.183.69.93
C0 A8 00 DC -> 192.168.0.220
計算:
4500 0031 89F5 0000 6e06 0000 DEB7 455D C0A8 00DC =3 22C4
0003 22C4 = 22C7
~22C7 = DD38 ->即爲應填充的校驗和
當接受到IP數據包時,要檢查IP頭是否正確,則對IP頭進行檢驗,方法同上:
計算:
4500 0031 89F5 0000 6E06 DD38 DEB7 455D C0A8 00DC =3 FFFC
0003 FFFC = FFFF
~FFFF = 00000 ->正確
TCP首部檢驗和與IP首部校驗和的計算方法基本相同,在程序中使用同一個函數來計算。
需要注意的是,由於TCP首部中不包含源地址與目標地址等信息,爲了保證TCP校驗的有效性,在進行TCP校驗和的計算時,需要增加一個TCP僞首部的校驗和,定義如下:
struct
{
unsigned long saddr; //源地址
unsigned long daddr; //目的地址
char mbz;//置空
char ptcl; //協議類型
unsigned short tcpl; //TCP長度
}psd_header;
然後我們將這兩個字段複製到同一個緩衝區SendBuf中並計算TCP校驗和:
memcpy(SendBuf,&psd_header,sizeof(psd_header));
memcpy(SendBuf sizeof(psd_header),&tcp_header,sizeof(tcp_header));
tcp_header.th_sum=checksum((USHORT *)SendBuf,sizeof(psd_header) sizeof(tcp_header));
uip裏通過if(uip_ipchksum() != 0xffff)來判斷是否校驗成功,當爲oxffff時,校驗成功
原文轉自:http://hi.baidu.com/xinjf/item/8f046ed95b762e3549e1dd19