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报头等长度 (编辑:源码网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |