clinuxtcplinux-kernelnetfilter

Difference between skb_header_pointer and skb_transport_header?


I'm trying to implement a netfilter module, while processing sk_buff I found two possible ways to retrieve TCP header:

struct iphdr *ip_header = (struct iphdr *)skb_network_header(skb);
struct tcphdr *tcp_header = (struct tcphdr *)skb_transport_header(skb);

And

struct iphdr *ip_header = skb_header_pointer(skb, 0, sizeof(struct iphdr), &_iph)
struct tcphdr *tcp_header = skb_header_pointer(skb, ip_header->ihl * 4, sizeof(struct tcphdr), &_tcph);

Which one should I use?


Solution

  • You should use ip_hdr() from /include/linux/ip.h and tcp_hdr() from /include/linux/tcp.h in case you know that there cannot be paged-skb here:

    struct iphdr *ip_header = ip_hdr(skb);
    if (ip_header->protocol == IPPROTO_TCP) {
        struct tcphdr *tcp_header = tcp_hdr(skb);
        //...
    

    skb_header_pointer() should be used in case the appearance of paged-skb is possible. Examples: IP, TCP, ICMP, etc.
    So if the header is in paged data (fully or partially) - skb_header_pointer() will correctly handle it.
    Also remember to check the return value of skb_header_pointer(), it can return NULL.

    Useful links: 1, 2