如何计算非线性skb / payload的TCP / UDP校验和?

时间:2014-05-11 21:35:24

标签: networking tcp linux-kernel udp linux-device-driver

我试图计算正在发送的skb上的TCP / UDP标头校验和。

基本上,有两个功能可以完成所有工作 (也在this stackoverflow questionthis one too中提及):

  • csum_tcpudp_magic
  • csum_partial

例如,对于TCP:

  tcph->check = 0;
  tcph->check = csum_tcpudp_magic(iph->saddr,
                                  iph->daddr,
                                  tcp_packet_len,
                                  IPPROTO_TCP,
                                  csum_partial((unsigned char *)tcph,
                                               tcp_packet_len,
                                               0));

这很好用 - 我能够传输TCP / UDP数据包并在接收端使用wireshark验证校验和。但是,我无法找到有关碎片化SKB的任何信息。

这两个魔法会不会出现? TCP / UDP有效负载碎片时的函数句柄

此外,TCP / UDP标头可能位于SKB的非线性部分(也是碎片)。

这些功能是否也会处理

我确实理解我可以尝试使用更大的数据包,这会导致它们碎片化,但现在错误处理的代价是内核oops,我无法将系统关闭。< / p>

2 个答案:

答案 0 :(得分:4)

经过大量的挖掘,我发现了这一点。 csum_tcpudp_magiccsum_partial无法使用碎片skb。 如果要使用它们来计算TCP / UDP校验和,我需要使所有数据包有效负载驻留在skb的线性部分。

幸运的是,Linux中有一个实用功能就是这样做 - skb_linearize

基本上,流程是:

  if (unlikely(skb_linearize(skb) != 0))
      ... goto drop - no memory...;

  ... do whatever you want with data ...
  tcph->check = 0;
  tcph->check = csum_tcpudp_magic(iph->saddr,
                                  iph->daddr,
                                  tcp_packet_len,
                                  IPPROTO_TCP,
                                  csum_partial((unsigned char *)tcph,
                                               tcp_packet_len,
                                               0));

如果无法进行线性化(性能,内存或其他原因),则需要手动计算校验和。

答案 1 :(得分:0)

此代码运行时,数据包已重新组装。