1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _NF_TABLES_IPV4_H_
3 #define _NF_TABLES_IPV4_H_
4 
5 #include <net/netfilter/nf_tables.h>
6 #include <net/ip.h>
7 
8 static inline void nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
9 					struct sk_buff *skb)
10 {
11 	struct iphdr *ip;
12 
13 	ip = ip_hdr(pkt->skb);
14 	pkt->tprot_set = true;
15 	pkt->tprot = ip->protocol;
16 	pkt->xt.thoff = ip_hdrlen(pkt->skb);
17 	pkt->xt.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
18 }
19 
20 static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt,
21 						  struct sk_buff *skb)
22 {
23 	struct iphdr *iph, _iph;
24 	u32 len, thoff;
25 
26 	iph = skb_header_pointer(skb, skb_network_offset(skb), sizeof(*iph),
27 				 &_iph);
28 	if (!iph)
29 		return -1;
30 
31 	if (iph->ihl < 5 || iph->version != 4)
32 		return -1;
33 
34 	len = ntohs(iph->tot_len);
35 	thoff = iph->ihl * 4;
36 	if (skb->len < len)
37 		return -1;
38 	else if (len < thoff)
39 		return -1;
40 
41 	pkt->tprot_set = true;
42 	pkt->tprot = iph->protocol;
43 	pkt->xt.thoff = thoff;
44 	pkt->xt.fragoff = ntohs(iph->frag_off) & IP_OFFSET;
45 
46 	return 0;
47 }
48 
49 static inline void nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt,
50 						 struct sk_buff *skb)
51 {
52 	if (__nft_set_pktinfo_ipv4_validate(pkt, skb) < 0)
53 		nft_set_pktinfo_unspec(pkt, skb);
54 }
55 
56 #endif
57