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
== 0 && !csum_fold(skb
->csum
)) ||
21 !csum_tcpudp_magic(iph
->saddr
, iph
->daddr
,
22 skb
->len
- dataoff
, protocol
,
24 skb
->ip_summed
= CHECKSUM_UNNECESSARY
;
32 skb
->csum
= csum_tcpudp_nofold(iph
->saddr
, iph
->daddr
,
35 csum
= __skb_checksum_complete(skb
);
39 EXPORT_SYMBOL(nf_ip_checksum
);
42 static __sum16
nf_ip_checksum_partial(struct sk_buff
*skb
, unsigned int hook
,
43 unsigned int dataoff
, unsigned int len
,
46 const struct iphdr
*iph
= ip_hdr(skb
);
49 switch (skb
->ip_summed
) {
50 case CHECKSUM_COMPLETE
:
51 if (len
== skb
->len
- dataoff
)
52 return nf_ip_checksum(skb
, hook
, dataoff
, protocol
);
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
);
63 __sum16
nf_ip6_checksum(struct sk_buff
*skb
, unsigned int hook
,
64 unsigned int dataoff
, u8 protocol
)
66 const struct ipv6hdr
*ip6h
= ipv6_hdr(skb
);
69 switch (skb
->ip_summed
) {
70 case CHECKSUM_COMPLETE
:
71 if (hook
!= NF_INET_PRE_ROUTING
&& hook
!= NF_INET_LOCAL_IN
)
73 if (!csum_ipv6_magic(&ip6h
->saddr
, &ip6h
->daddr
,
74 skb
->len
- dataoff
, protocol
,
78 skb
->ip_summed
= CHECKSUM_UNNECESSARY
;
83 skb
->csum
= ~csum_unfold(
84 csum_ipv6_magic(&ip6h
->saddr
, &ip6h
->daddr
,
90 csum
= __skb_checksum_complete(skb
);
94 EXPORT_SYMBOL(nf_ip6_checksum
);
96 static __sum16
nf_ip6_checksum_partial(struct sk_buff
*skb
, unsigned int hook
,
97 unsigned int dataoff
, unsigned int len
,
100 const struct ipv6hdr
*ip6h
= ipv6_hdr(skb
);
104 switch (skb
->ip_summed
) {
105 case CHECKSUM_COMPLETE
:
106 if (len
== skb
->len
- dataoff
)
107 return nf_ip6_checksum(skb
, hook
, dataoff
, protocol
);
110 hsum
= skb_checksum(skb
, 0, dataoff
, 0);
111 skb
->csum
= ~csum_unfold(csum_ipv6_magic(&ip6h
->saddr
,
116 skb
->ip_summed
= CHECKSUM_NONE
;
117 return __skb_checksum_complete_head(skb
, dataoff
+ len
);
122 __sum16
nf_checksum(struct sk_buff
*skb
, unsigned int hook
,
123 unsigned int dataoff
, u8 protocol
,
124 unsigned short family
)
130 csum
= nf_ip_checksum(skb
, hook
, dataoff
, protocol
);
133 csum
= nf_ip6_checksum(skb
, hook
, dataoff
, protocol
);
139 EXPORT_SYMBOL_GPL(nf_checksum
);
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
)
149 csum
= nf_ip_checksum_partial(skb
, hook
, dataoff
, len
,
153 csum
= nf_ip6_checksum_partial(skb
, hook
, dataoff
, len
,
160 EXPORT_SYMBOL_GPL(nf_checksum_partial
);
162 int nf_route(struct net
*net
, struct dst_entry
**dst
, struct flowi
*fl
,
163 bool strict
, unsigned short family
)
165 const struct nf_ipv6_ops
*v6ops
;
170 ret
= nf_ip_route(net
, dst
, fl
, strict
);
173 v6ops
= rcu_dereference(nf_ipv6_ops
);
175 ret
= v6ops
->route(net
, dst
, fl
, strict
);
181 EXPORT_SYMBOL_GPL(nf_route
);
183 int nf_reroute(struct sk_buff
*skb
, struct nf_queue_entry
*entry
)
185 const struct nf_ipv6_ops
*v6ops
;
188 switch (entry
->state
.pf
) {
190 ret
= nf_ip_reroute(skb
, entry
);
193 v6ops
= rcu_dereference(nf_ipv6_ops
);
195 ret
= v6ops
->reroute(skb
, entry
);