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);