IP 首部校验和的计算 zz

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

IP 首部校验和的计算zz

1IP数据包的头信息格式:

+-------------------------------------------------+

| 版本 (4位) |

+-------------------------------------------------+

| 首部长度(4位) |

+-------------------------------------------------+

| 服务类型(TOS)8位 |

+-------------------------------------------------+

| 数据包总长度(16位) |

+-------------------------------------------------+

| 标识ID号(16位) |

+-------------------------------------------------+

| 标志位(3位) |

+-------------------------------------------------+

| 片偏移(13位) |

+-------------------------------------------------+

| 生存时间(TTL)(8位) |

+-------------------------------------------------+

| 协议类型 (8位) |

+-------------------------------------------------+

| 首部校验和(16位) |

+-------------------------------------------------+

| 源IP地址(32位) |

+-------------------------------------------------+

| 目的IP地址 (32位) |

+-------------------------------------------------+

* IP选项(若有) (32位) *

+-------------------------------------------------+

* 数据 *

+-------------------------------------------------+

这里要说的是首部校验和字段。

在发送数据时,为了计算数IP据报的校验和。应该按如下步骤:

(1)把IP数据报的首部都置为0,包括校验和字段。

(2)把首部看成以16位为单位的数字组成,依次进行二进制反码求和。

(3)把得到的结果存入校验和字段中。

在接收数据时,计算数据报的校验和相对简单,按如下步骤:

(1)把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段。(2)检查计算出的校验和的结果是否等于零。

(3)如果等于零,说明被整除,校验是和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包。

首先,查看了Linux 2.6内核中的校验算法,使用汇编语言编写的,显然效率要高些。代码如下:

unsigned short ip_fast_csum(unsigned char * iph,

unsigned int ihl)

{

unsigned int sum;

__asm__ __volatile__(

"movl (%1), %0 ;\n"

"subl $4, %2 ;\n"

"jbe 2f ;\n"

"addl 4(%1), %0 ;\n"

"adcl 8(%1), %0 ;\n"

"adcl 12(%1), %0 ;\n"

"1: adcl 16(%1), %0 ;\n"

"lea 4(%1), %1 ;\n"

"decl %2 ;\n"

"jne 1b ;\n"

"adcl $0, %0 ;\n"

"movl %0, %2 ;\n"

"shrl $16, %0 ;\n"

"addw %w2, %w0 ;\n"

"adcl $0, %0 ;\n"

"notl %0 ;\n"

"2: ;\n"

/* Since the input registers which are loaded with iph and ihl

are modified, we must also specify them as outputs, or gcc

will assume they contain their original values. */

: "=r" (sum), "=r" (iph), "=r" (ihl)

: "1" (iph), "2" (ihl)

: "memory");

return(sum);

}

在这个函数中,第一个参数显然就是IP数据报的首地址,所有算法几乎一样。需要注意的是第二个参数,它是直接使用IP数据报头信息中的首部长度字段,不需要进行转换,因此,速度又快了(高手就是考虑的周到)。使用方法会在下面的例子代码中给出。

第二种算法就非常普通了,是用C语言编写的。我看了许多实现网络协议栈的代码,这个算法是最常用的了,即使变化,也无非是先取反后取和之类的。考虑其原因,估计还是C语言的移植性更好吧。下面是该函数的实现:

unsigned short checksum(unsigned short *buf,int nword)

{

unsigned long sum;

for(sum=0;nword>0;nword--)

sum += *buf++;

sum = (sum>>16) + (sum&0xffff);

相关文档
最新文档