Multiple places in the net stack open-code the same minimal IPv4 header validation: pull the fixed header, check version 4 and IHL >= 5 (where 5 is the fixed header size in 32-bit units) - and locate the transport header at IHL * 4 past the network header.
Add a helper for doing that: it returns the validated header and the transport header offset, or NULL if truncated or malformed. Signed-off-by: Michael S. Tsirkin <[email protected]> Assisted-by: LLM --- include/linux/ip.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/linux/ip.h b/include/linux/ip.h index d11c25f5030a0..98012f6d0efb5 100644 --- a/include/linux/ip.h +++ b/include/linux/ip.h @@ -56,4 +56,28 @@ static inline void iph_set_totlen(struct iphdr *iph, unsigned int len) { iph->tot_len = len <= IP_MAX_MTU ? htons(len) : 0; } + +/* + * Pull and minimally validate the IPv4 header at @nhoff. + * Returns the header and stores the transport header offset in + * @thoff, or NULL if truncated or malformed. Only the fixed header + * is guaranteed linear; callers that need the options or the + * transport header must pull further. + */ +static inline struct iphdr *ip4_parse(struct sk_buff *skb, + unsigned int nhoff, + unsigned int *thoff) +{ + struct iphdr *iph; + + if (!pskb_may_pull(skb, nhoff + sizeof(struct iphdr))) + return NULL; + + iph = (struct iphdr *)(skb->data + nhoff); + if (iph->version != 4 || iph->ihl < sizeof(struct iphdr) / sizeof(u32)) + return NULL; + + *thoff = nhoff + iph->ihl * sizeof(u32); + return iph; +} #endif /* _LINUX_IP_H */ -- MST

