Linux内核分析 - 网络[十一]:ICMP模块
|
icmp_push_reply() 发送回复报文 取出icmp使用的sock sk sk = icmp_sk(dev_net((*rt)- >u.dst.dev)); if中的ip_append_data()函数表示把数据添加到sk->sk_write_queue,这个函数是用于上层向IP层 传输报文,它会进行分片的操作,实际是帮IP层做了分片。具体函数调用参见后面的ip_append_data()函数分析。正常情况 ip_append_data()返回0,即if的执行语句不会被触发。
if (ip_append_data(sk, icmp_glue_bits, icmp_param,
icmp_param->data_len+icmp_param->head_len,
icmp_param->head_len,
ipc, rt, MSG_DONTWAIT) < 0)
ip_flush_pending_frames(sk);
else if进入条件是sk->sk_write_queue中已有数据,显然在if的判断语句中已 经将报文添加到了sk->sk_write_queue中,所以会进入else if执行语句调用ip_push_pending_frames()将报文传递给IP层。 而在ip_append_data()函数中可以看到,它只是拷贝了报文内容,并没有生成ICMP报头,ICMP报头生成当然也是在通过 ip_push_pending_frames()将报文发给IP层前生成的。取出skb,计算所有分片一起的校验和,然过通过 csum_partial_copy_nocheck()生成新的icmp报头,最后调用ip_push_pending_frames()发送数据到IP层。函数 ip_push_pending_frames()函数分析也参见后文。
else if ((skb = skb_peek(&sk->sk_write_queue)) !=
NULL) {
struct icmphdr *icmph = icmp_hdr(skb);
__wsum csum = 0;
struct sk_buff *skb1;
skb_queue_walk(&sk->sk_write_queue, skb1) {
sum = csum_add(csum, skb1->csum);
}
csum = csum_partial_copy_nocheck((void *)&icmp_param->data,
(char *)icmph,
icmp_param->head_len, csum);
icmph->checksum = csum_fold(csum);
skb->ip_summed = CHECKSUM_NONE;
ip_push_pending_frames(sk);
}
ip_append_data() 添加要传递到IP层的数据 传入参数的解释: getfrag() – 复制数据,这里使用函数指针 隐藏了复制细节,因为针对icmp, udp的复制是不同的; from – 被复制的数据,在icmp模块中该参数传入的是struct icmp_bxm; length – IP报文内容长度 transhdrlen – 传输报头长度,尽管ICMP归为网络层协议,但这里的transhdrlen 也是包括它的,所以更好的解释是表示IP上一层的报头,比如ICMP报头,IGMP报头,UDP报头等长度
(编辑:宣城站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

![Linux内核分析 - 网络[十一]:ICMP模块](http://img16.aspzz.cn/uploads/allimg/c160921/14J46342112J0-25609.gif)

