CH395 组播应用补充(2)

阅读本文前请先阅读下方链接文章了解组播应用流程,本文是对其的补充说明

CH395 组播应用补充(1) - Lqqq123 - 博客园

阅读完上述文章后,可以发现,当用CH395的IPRAW模式组IGMP包定期加入某一组时,这个所组的IGMP入组包中的检验和字段(2字节)是先随机填入一个值,再根据wireshark算出来的实际值填入,本文就是针对此处提供一个校验字段的算法,供使用参考。

 

如下,是一个完整的需要发出的入组包,其中0x95,0x29是两字节的校验和

1 UINT8  MyBuffer[16] = {
2                           0x22,0x00,
3                           0x95,0x29,
4                           0x00,0x00,0x00,0x01,
5                           0x04,0x00,0x00,0x00,
6                           0xe0,0x64,0x64,0x70,//224.100.100.112
7                         };//调用send函数用ipRaw模式的socket将这一包数据发出即可加入组播:CH395SendData(sock_id,MyBuffer,sizeof(MyBuffer));

那是如何算出来的?

1.首先将校验和字段置0,及把0x95,0x29写为0x00,0x00

2.将数据分为16位进行相加(若产生进位,则将进位加到最低位)

比如上面的数据包,先将数据按16位分组,即分为:0x2200,0x0000,0x0000,0x0001,0x0400,0x0000,0xe064,0x6470

然后按位相加:

0x2200+0x0000+0x0000+0x0001+0x0400+0x0000+0xe064 = 0x10665,注意到此时已经超过了16位产生了进位,所以要先将进位加到最低位,如下

0x10665 = 0001 0000 0110 0110 0101(二进制),即0000 0110 0110 0101(低16位) + 0001(剩下的高位) = 0000 0110 0110 0110  = 0x0666;

 

再加上之前剩下的一个0x6470,

即0x0666+ 0x6470 = 0x6A6D = 0110 1010 1101 0110 

全部算完后取反:                   = 1001 0101 0010 1001 = 0x9529

可以看到,最后算出来的检验和字段和之前对的上,就是0x95 0x29

最后将算出来的校验值填入数据中的对应位置即可。

 

附上实现代码供参考:

 1 // 计算IGMP校验和的函数
 2     uint16_t calculate_igmp_checksum(const uint8_t *packet, size_t length) {
 3     uint32_t sum = 0;
 4     const uint16_t *data = (const uint16_t *)packet;
 5     size_t i;
 6     // 确保长度是偶数,如果不是则补零
 7     if (length % 2 == 1) {
 8         length++;       
 9     }
10     // 对数据按16位进行累加
11     for (i = 0; i < length / 2; i++) {
12         sum += data[i];     
13         while (sum >> 16) {
14             sum = (sum & 0xFFFF) + (sum >> 16);    // 处理进位
15         }
16     }    
17     sum = ~sum;                // 对累加和取反
18     return (uint16_t)sum;
19 }
20 int main() {
21     // 示例
22     uint8_t igmp_packet[] = {
23         0x22,0x00,
24         0x00,0x00,                //校验位先置0
25         0x00,0x00,0x00,0x01,
26         0x04,0x00,0x00,0x00,
27         0xe0,0x64,0x64,0x70,          //224.100.100.112
28     };            
29     size_t packet_length = sizeof(igmp_packet);
30     uint16_t checksum = calculate_igmp_checksum(igmp_packet, packet_length);
31     printf("IGMP Checksum: 0x%04X\n", checksum);
32     return 0;
33 }

 

posted on 2025-04-12 13:36  Lqqq123  阅读(50)  评论(0)    收藏  举报

导航