]> git.proxmox.com Git - mirror_ubuntu-disco-kernel.git/blob - net/netfilter/utils.c
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-disco-kernel.git] / net / netfilter / utils.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/kernel.h>
3 #include <linux/netfilter.h>
4 #include <linux/netfilter_ipv4.h>
5 #include <linux/netfilter_ipv6.h>
6 #include <net/netfilter/nf_queue.h>
7 #include <net/ip6_checksum.h>
8
9 #ifdef CONFIG_INET
10 __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
11 unsigned int dataoff, u8 protocol)
12 {
13 const struct iphdr *iph = ip_hdr(skb);
14 __sum16 csum = 0;
15
16 switch (skb->ip_summed) {
17 case CHECKSUM_COMPLETE:
18 if (hook != NF_INET_PRE_ROUTING && hook != NF_INET_LOCAL_IN)
19 break;
20 if ((protocol == 0 && !csum_fold(skb->csum)) ||
21 !csum_tcpudp_magic(iph->saddr, iph->daddr,
22 skb->len - dataoff, protocol,
23 skb->csum)) {
24 skb->ip_summed = CHECKSUM_UNNECESSARY;
25 break;
26 }
27 /* fall through */
28 case CHECKSUM_NONE:
29 if (protocol == 0)
30 skb->csum = 0;
31 else
32 skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
33 skb->len - dataoff,
34 protocol, 0);
35 csum = __skb_checksum_complete(skb);
36 }
37 return csum;
38 }
39 EXPORT_SYMBOL(nf_ip_checksum);
40 #endif
41
42 static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook,
43 unsigned int dataoff, unsigned int len,
44 u8 protocol)
45 {
46 const struct iphdr *iph = ip_hdr(skb);
47 __sum16 csum = 0;
48
49 switch (skb->ip_summed) {
50 case CHECKSUM_COMPLETE:
51 if (len == skb->len - dataoff)
52 return nf_ip_checksum(skb, hook, dataoff, protocol);
53 /* fall through */
54 case CHECKSUM_NONE:
55 skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, protocol,
56 skb->len - dataoff, 0);
57 skb->ip_summed = CHECKSUM_NONE;
58 return __skb_checksum_complete_head(skb, dataoff + len);
59 }
60 return csum;
61 }
62
63 __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
64 unsigned int dataoff, u8 protocol)
65 {
66 const struct ipv6hdr *ip6h = ipv6_hdr(skb);
67 __sum16 csum = 0;
68
69 switch (skb->ip_summed) {
70 case CHECKSUM_COMPLETE:
71 if (hook != NF_INET_PRE_ROUTING && hook != NF_INET_LOCAL_IN)
72 break;
73 if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
74 skb->len - dataoff, protocol,
75 csum_sub(skb->csum,
76 skb_checksum(skb, 0,
77 dataoff, 0)))) {
78 skb->ip_summed = CHECKSUM_UNNECESSARY;
79 break;
80 }
81 /* fall through */
82 case CHECKSUM_NONE:
83 skb->csum = ~csum_unfold(
84 csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
85 skb->len - dataoff,
86 protocol,
87 csum_sub(0,
88 skb_checksum(skb, 0,
89 dataoff, 0))));
90 csum = __skb_checksum_complete(skb);
91 }
92 return csum;
93 }
94 EXPORT_SYMBOL(nf_ip6_checksum);
95
96 static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook,
97 unsigned int dataoff, unsigned int len,
98 u8 protocol)
99 {
100 const struct ipv6hdr *ip6h = ipv6_hdr(skb);
101 __wsum hsum;
102 __sum16 csum = 0;
103
104 switch (skb->ip_summed) {
105 case CHECKSUM_COMPLETE:
106 if (len == skb->len - dataoff)
107 return nf_ip6_checksum(skb, hook, dataoff, protocol);
108 /* fall through */
109 case CHECKSUM_NONE:
110 hsum = skb_checksum(skb, 0, dataoff, 0);
111 skb->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr,
112 &ip6h->daddr,
113 skb->len - dataoff,
114 protocol,
115 csum_sub(0, hsum)));
116 skb->ip_summed = CHECKSUM_NONE;
117 return __skb_checksum_complete_head(skb, dataoff + len);
118 }
119 return csum;
120 };
121
122 __sum16 nf_checksum(struct sk_buff *skb, unsigned int hook,
123 unsigned int dataoff, u8 protocol,
124 unsigned short family)
125 {
126 __sum16 csum = 0;
127
128 switch (family) {
129 case AF_INET:
130 csum = nf_ip_checksum(skb, hook, dataoff, protocol);
131 break;
132 case AF_INET6:
133 csum = nf_ip6_checksum(skb, hook, dataoff, protocol);
134 break;
135 }
136
137 return csum;
138 }
139 EXPORT_SYMBOL_GPL(nf_checksum);
140
141 __sum16 nf_checksum_partial(struct sk_buff *skb, unsigned int hook,
142 unsigned int dataoff, unsigned int len,
143 u8 protocol, unsigned short family)
144 {
145 __sum16 csum = 0;
146
147 switch (family) {
148 case AF_INET:
149 csum = nf_ip_checksum_partial(skb, hook, dataoff, len,
150 protocol);
151 break;
152 case AF_INET6:
153 csum = nf_ip6_checksum_partial(skb, hook, dataoff, len,
154 protocol);
155 break;
156 }
157
158 return csum;
159 }
160 EXPORT_SYMBOL_GPL(nf_checksum_partial);
161
162 int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
163 bool strict, unsigned short family)
164 {
165 const struct nf_ipv6_ops *v6ops;
166 int ret = 0;
167
168 switch (family) {
169 case AF_INET:
170 ret = nf_ip_route(net, dst, fl, strict);
171 break;
172 case AF_INET6:
173 v6ops = rcu_dereference(nf_ipv6_ops);
174 if (v6ops)
175 ret = v6ops->route(net, dst, fl, strict);
176 break;
177 }
178
179 return ret;
180 }
181 EXPORT_SYMBOL_GPL(nf_route);
182
183 int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry)
184 {
185 const struct nf_ipv6_ops *v6ops;
186 int ret = 0;
187
188 switch (entry->state.pf) {
189 case AF_INET:
190 ret = nf_ip_reroute(skb, entry);
191 break;
192 case AF_INET6:
193 v6ops = rcu_dereference(nf_ipv6_ops);
194 if (v6ops)
195 ret = v6ops->reroute(skb, entry);
196 break;
197 }
198 return ret;
199 }