Merge tag 'kernel.sys.v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner...
[linux-2.6-microblaze.git] / include / net / netfilter / nf_tables_ipv4.h
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 {
10         struct iphdr *ip;
11
12         ip = ip_hdr(pkt->skb);
13         pkt->flags = NFT_PKTINFO_L4PROTO;
14         pkt->tprot = ip->protocol;
15         pkt->thoff = ip_hdrlen(pkt->skb);
16         pkt->fragoff = ntohs(ip->frag_off) & IP_OFFSET;
17 }
18
19 static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
20 {
21         struct iphdr *iph, _iph;
22         u32 len, thoff;
23
24         iph = skb_header_pointer(pkt->skb, skb_network_offset(pkt->skb),
25                                  sizeof(*iph), &_iph);
26         if (!iph)
27                 return -1;
28
29         if (iph->ihl < 5 || iph->version != 4)
30                 return -1;
31
32         len = ntohs(iph->tot_len);
33         thoff = iph->ihl * 4;
34         if (pkt->skb->len < len)
35                 return -1;
36         else if (len < thoff)
37                 return -1;
38
39         pkt->flags = NFT_PKTINFO_L4PROTO;
40         pkt->tprot = iph->protocol;
41         pkt->thoff = thoff;
42         pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET;
43
44         return 0;
45 }
46
47 static inline void nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
48 {
49         if (__nft_set_pktinfo_ipv4_validate(pkt) < 0)
50                 nft_set_pktinfo_unspec(pkt);
51 }
52
53 static inline int nft_set_pktinfo_ipv4_ingress(struct nft_pktinfo *pkt)
54 {
55         struct iphdr *iph;
56         u32 len, thoff;
57
58         if (!pskb_may_pull(pkt->skb, sizeof(*iph)))
59                 return -1;
60
61         iph = ip_hdr(pkt->skb);
62         if (iph->ihl < 5 || iph->version != 4)
63                 goto inhdr_error;
64
65         len = ntohs(iph->tot_len);
66         thoff = iph->ihl * 4;
67         if (pkt->skb->len < len) {
68                 __IP_INC_STATS(nft_net(pkt), IPSTATS_MIB_INTRUNCATEDPKTS);
69                 return -1;
70         } else if (len < thoff) {
71                 goto inhdr_error;
72         }
73
74         pkt->flags = NFT_PKTINFO_L4PROTO;
75         pkt->tprot = iph->protocol;
76         pkt->thoff = thoff;
77         pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET;
78
79         return 0;
80
81 inhdr_error:
82         __IP_INC_STATS(nft_net(pkt), IPSTATS_MIB_INHDRERRORS);
83         return -1;
84 }
85
86 #endif