一.CRC 硬件实现。
上次作业中用程序实现了 CRC 的算法,而计算机硬件也已经实现了 CRC 的
算法,所以需要把模二运算的过程转化为硬件容易实现的算法,目前广泛使用的
就是通过移位寄存器的移位和对应位的异或来实现 CRC 检验的,这里我用
CRC-8 做演示,其他的原理相同。
对 CRC-8 来说需要 8 个寄存器,3 个异或运算,因为 CRC-8 的生成多项式是
其中 R0 表示常数项 1,R1 表示一次项,R2 表示 2 次项 .
下图是用 visio 画的硬件寄存器实现 CRC-8 的算法示意图:
可以看到,最后原始数据 1101 经过 CRC-8 得出的 FCS 为 00100011,下面将会验
证其正确性。
我利用上次作业编写的 CRC 模二运算实现的代码检验上述硬件实现过程的正确
性,可以看到下图,经验证,它们是一致的,即正确的 FCS 就是 00100011。
二.Ip 数据报首部检验和的程序实现。
首先我利用 wireshark 抓了若干个数据报,随便点开了一个协议为 TCP 的数据报,
见以下几个图。
由上图可以看出该数据报的检验和经 wireshark 验证正确为 0x8f45.
然后我利用网络上的检验和 CheckSum 函数和自己编写的 main 函数实现对该
数据报的首部除检验和位的所有 18 个字节的输入,并计算出检验和:
程序代码如下:
#include
#include
typedef unsigned short USHORT;
typedef unsigned char UCHAR;
void main()
{
USHORT CheckSum(USHORT *, int);
int s;
char
iphead[50]={0x00,0x45,0x90,0x00,0x21,0x6b,0x00,0x40,0x06,0x3d,0x9b,0x73,0xd1,0x30,0x9b,0x
73,0xfa,0x2a};
//这里根据我所抓的包内首部出了检验和的所有字节对应 16 进制数放到数
组 iphead 里面。
USHORT sum;
s=18;
//因为这里首部为一般情况的 20 个字节,去除检验和的 2 个字节,还有 18 个字
//定义 sum 为最后的检验核数。
节,即 s 指示总字节数 18。
sum=CheckSum((USHORT*)iphead,s);
printf("%x\n",sum);
}
USHORT CheckSum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while (size > 1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
if (size)
{
cksum += *(UCHAR*)buffer;
//如果总字节数为奇数,则将最后一个字节用 buffer
强制转换后进行求和。
}
//对每个 16bit 进行二进制反码求和
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
//返回最后检验和结果。
}
程序运行结果如下:
和所抓包对比可知,该检验和是正确的。