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>
10 __sum16
nf_ip_checksum(struct sk_buff
*skb
, unsigned int hook
,
11 unsigned int dataoff
, u8 protocol
)
13 const struct iphdr
*iph
= ip_hdr(skb
);
16 switch (skb
->ip_summed
) {
17 case CHECKSUM_COMPLETE
:
18 if (hook
!= NF_INET_PRE_ROUTING
&& hook
!= NF_INET_LOCAL_IN
)
20 if ((protocol
!= IPPROTO_TCP
&& protocol
!= IPPROTO_UDP
&&
21 !csum_fold(skb
->csum
)) ||
22 !csum_tcpudp_magic(iph
->saddr
, iph
->daddr
,
23 skb
->len
- dataoff
, protocol
,
25 skb
->ip_summed
= CHECKSUM_UNNECESSARY
;
30 if (protocol
!= IPPROTO_TCP
&& protocol
!= IPPROTO_UDP
)
33 skb
->csum
= csum_tcpudp_nofold(iph
->saddr
, iph
->daddr
,
36 csum
= __skb_checksum_complete(skb
);
40 EXPORT_SYMBOL(nf_ip_checksum
);
43 static __sum16
nf_ip_checksum_partial(struct sk_buff
*skb
, unsigned int hook
,
44 unsigned int dataoff
, unsigned int len
,
47 const struct iphdr
*iph
= ip_hdr(skb
);
50 switch (skb
->ip_summed
) {
51 case CHECKSUM_COMPLETE
:
52 if (len
== skb
->len
- dataoff
)
53 return nf_ip_checksum(skb
, hook
, dataoff
, protocol
);
56 skb
->csum
= csum_tcpudp_nofold(iph
->saddr
, iph
->daddr
, protocol
,
57 skb
->len
- dataoff
, 0);
58 skb
->ip_summed
= CHECKSUM_NONE
;
59 return __skb_checksum_complete_head(skb
, dataoff
+ len
);
64 __sum16
nf_ip6_checksum(struct sk_buff
*skb
, unsigned int hook
,
65 unsigned int dataoff
, u8 protocol
)
67 const struct ipv6hdr
*ip6h
= ipv6_hdr(skb
);
70 switch (skb
->ip_summed
) {
71 case CHECKSUM_COMPLETE
:
72 if (hook
!= NF_INET_PRE_ROUTING
&& hook
!= NF_INET_LOCAL_IN
)
74 if (!csum_ipv6_magic(&ip6h
->saddr
, &ip6h
->daddr
,
75 skb
->len
- dataoff
, protocol
,
79 skb
->ip_summed
= CHECKSUM_UNNECESSARY
;
84 skb
->csum
= ~csum_unfold(
85 csum_ipv6_magic(&ip6h
->saddr
, &ip6h
->daddr
,
91 csum
= __skb_checksum_complete(skb
);
95 EXPORT_SYMBOL(nf_ip6_checksum
);
97 static __sum16
nf_ip6_checksum_partial(struct sk_buff
*skb
, unsigned int hook
,
98 unsigned int dataoff
, unsigned int len
,
101 const struct ipv6hdr
*ip6h
= ipv6_hdr(skb
);
105 switch (skb
->ip_summed
) {
106 case CHECKSUM_COMPLETE
:
107 if (len
== skb
->len
- dataoff
)
108 return nf_ip6_checksum(skb
, hook
, dataoff
, protocol
);
111 hsum
= skb_checksum(skb
, 0, dataoff
, 0);
112 skb
->csum
= ~csum_unfold(csum_ipv6_magic(&ip6h
->saddr
,
117 skb
->ip_summed
= CHECKSUM_NONE
;
118 return __skb_checksum_complete_head(skb
, dataoff
+ len
);
123 __sum16
nf_checksum(struct sk_buff
*skb
, unsigned int hook
,
124 unsigned int dataoff
, u8 protocol
,
125 unsigned short family
)
131 csum
= nf_ip_checksum(skb
, hook
, dataoff
, protocol
);
134 csum
= nf_ip6_checksum(skb
, hook
, dataoff
, protocol
);
140 EXPORT_SYMBOL_GPL(nf_checksum
);
142 __sum16
nf_checksum_partial(struct sk_buff
*skb
, unsigned int hook
,
143 unsigned int dataoff
, unsigned int len
,
144 u8 protocol
, unsigned short family
)
150 csum
= nf_ip_checksum_partial(skb
, hook
, dataoff
, len
,
154 csum
= nf_ip6_checksum_partial(skb
, hook
, dataoff
, len
,
161 EXPORT_SYMBOL_GPL(nf_checksum_partial
);
163 int nf_route(struct net
*net
, struct dst_entry
**dst
, struct flowi
*fl
,
164 bool strict
, unsigned short family
)
166 const struct nf_ipv6_ops
*v6ops __maybe_unused
;
171 ret
= nf_ip_route(net
, dst
, fl
, strict
);
174 ret
= nf_ip6_route(net
, dst
, fl
, strict
);
180 EXPORT_SYMBOL_GPL(nf_route
);
182 static int nf_ip_reroute(struct sk_buff
*skb
, const struct nf_queue_entry
*entry
)
185 const struct ip_rt_info
*rt_info
= nf_queue_entry_reroute(entry
);
187 if (entry
->state
.hook
== NF_INET_LOCAL_OUT
) {
188 const struct iphdr
*iph
= ip_hdr(skb
);
190 if (!(iph
->tos
== rt_info
->tos
&&
191 skb
->mark
== rt_info
->mark
&&
192 iph
->daddr
== rt_info
->daddr
&&
193 iph
->saddr
== rt_info
->saddr
))
194 return ip_route_me_harder(entry
->state
.net
, skb
,
201 int nf_reroute(struct sk_buff
*skb
, struct nf_queue_entry
*entry
)
203 const struct nf_ipv6_ops
*v6ops
;
206 switch (entry
->state
.pf
) {
208 ret
= nf_ip_reroute(skb
, entry
);
211 v6ops
= rcu_dereference(nf_ipv6_ops
);
213 ret
= v6ops
->reroute(skb
, entry
);