Frage

I'm trying to calculate TCP/UDP headers checksum on an skb that is being sent out.

Basically, there are two functions that are supposed to do all the work (mentioned also in this stackoverflow question and this one too):

  • csum_tcpudp_magic
  • csum_partial

For instance, for 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));

This works fine - I'm able to transmit TCP/UDP packets and validate checksum with wireshark on the receive side. However, I couldn't find any info regarding fragmented SKB.

Will these two 'magic' function handle cases when TCP/UDP payload is fragmented?

Also, it is possible that TCP/UDP headers might reside in a non-linear part of the SKB (fragmented as well).

Will such case be handled too by these functions?

I do understand that I can just try it with larger packets, which will cause them to be fragmented, but the price of wrong handling right now would be kernel oops, and I can't bring the system down.

War es hilfreich?

Lösung

After lots of digging I figured this out. csum_tcpudp_magic and csum_partial can't work with fragmented skb. If you want to use them to calculate TCP/UDP checksums, I need to make all the packet payload to reside in the linear part of the skb.

Luckily, there's a utility function in Linux that does just that - skb_linearize.

So basically, the flow is:

  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));

If linearization is not possible (performance, memory, or whatever reason), then you need to calculate the checksum 'manually'.

Andere Tipps

By the time this code runs the packet has been reassembled.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top