循环冗余码校验英文名称为Cyclical Redundancy Check,简称CRC。它是利用除法及余数的原理来作错误侦测(Error Detecting)的。实际应用时,发送装置计算出CRC值并随数据一同发送给接收装置,接收装置对收到的数据重新计算CRC并与收到的CRC相比较,若两个CRC值不同,则说明数据通讯出现错误。
CRC-16码由两个字节构成,在开始时CRC寄存器的每一位都预置为1,然后把CRC寄存器与8-bit的数据进行异或,之后对CRC寄存器从高到低进行移位,在最高位(MSB)的位置补零,而最低位(LSB,移位后已经被移出CRC寄存器)如果为1,则把寄存器与预定义的多项式码进行异或,否则如果 LSB为零,则无需进行异或。重复上述的由高至低的移位8次,第一个8-bit数据处理完毕,用此时CRC寄存器的值与下一个8-bit数据异或并进行如前一个数据似的8次移位。所有的字符处理完成后CRC寄存器内的值即为最终的CRC值。
下面为CRC16的计算过程,其中生成多项式为:X16+X15+X2+1:
1.设置CRC寄存器,并给其赋值FFFF(hex)。
2.将数据的第一个8-bit字符与16位CRC寄存器的低8位进行异或,并把结果存入CRC寄存器。
3.CRC寄存器向右移一位,MSB补零,移出并检查LSB。
4.如果LSB为0,重复第三步;若LSB为1,CRC寄存器与生成多项式码相异或。
5.重复第3与第4步直到8次移位全部完成。此时一个8-bit数据处理完毕。
6.重复第2至第5步直到所有数据全部处理完成。
7.最终CRC寄存器的内容即为CRC值。
/******************************************************************
CRC16校验和计算icmp_cksum
参数:
data:数据
len:数据长度
返回值:
计算结果,short类型
******************************************************************/
static unsigned short icmp_cksum(unsigned char *data, int len)
{
int sum=0;
int odd = len & 0x01;/*是否为奇数*/
unsigned short *value = (unsigned short*)data;
/*将数据按照2字节为单位累加起来*/
while( len & 0xfffe) {
sum += *(unsigned short*)data;
data += 2;
len -=2;
}
/*判断是否为奇数个数据,若ICMP报头为奇数个字节,会剩下最后一字节。*/
if( odd) {
unsigned short tmp = ((*data)<<8)&0xff00;
sum += tmp;
}
sum = (sum >>16) + (sum & 0xffff);
sum += (sum >>16) ;
return ~sum;
}