I am writing a network module in Linux, and I see that the tcp header can be extracted only after skipping 20 bytes from the skb buffer, even though the API is 'skb_transport_header'.
What is the reason behind it? Can some body please explain in detail? The same is not required for outgoing packets. I understand that while receiving the packets, the headers are removed as the packet flows from L1 to L5. However, when the packet is outgoing, the headers are added. How this makes a difference here?
/**For Input packet **/
struct tcphdr *tcp;
tcp = (struct tcphdr *)(skb_transport_header(skb)+20);
/** For Outgoing packet **/
struct tcphdr *tcp;
tcp = (struct tcphdr *)(skb_transport_header(skb));
It depends on where in the stack you process the packet. Just after receipt of the packet, the transport header offset won't yet have been set. Once you've gotten to the point where it's been determined that this packet is in fact destined to the local box, that should no longer be necessary. This happens for IPv4 in ip_local_deliver_finish(). (Note that tcp_hdr(), for example, assumes that the transport_header location is already set.)
This makes total sense (even though it can be hard to determine where things like this happen in the normal flow): As each layer is recognized and processed, the starting offset of the next layer is recorded in the sk_buff. The headers aren't actually removed, the skb "data" location is just adjusted to point beyond them. And the layer-specific location is similarly adjusted.
On output, it's a little more straightforward and is done in the opposite order: transport header will be created first. Then, the network header is prepended to that, etc.