aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2006-04-06 17:18:43 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-04-10 01:25:41 -0400
commit422c346fad806e2abaeffac686860ebc98dfe33e (patch)
treedd554d11e80ad33afef4b438ec4c2d8943ad37f4 /net
parentbce8032ef3cc58170ab3550e9e271dba7b4c4764 (diff)
[NETFILTER]: Add address family specific checksum helpers
Add checksum operation which takes care of verifying the checksum and dealing with HW checksum errors and avoids multiple checksum operations by setting ip_summed to CHECKSUM_UNNECESSARY after successful verification. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/netfilter.c33
-rw-r--r--net/ipv6/netfilter.c34
2 files changed, 67 insertions, 0 deletions
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index b25339c11ea0..6a9e34b794bc 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -161,8 +161,41 @@ static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info)
161 return 0; 161 return 0;
162} 162}
163 163
164unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
165 unsigned int dataoff, u_int8_t protocol)
166{
167 struct iphdr *iph = skb->nh.iph;
168 unsigned int csum = 0;
169
170 switch (skb->ip_summed) {
171 case CHECKSUM_HW:
172 if (hook != NF_IP_PRE_ROUTING && hook != NF_IP_LOCAL_IN)
173 break;
174 if ((protocol == 0 && !(u16)csum_fold(skb->csum)) ||
175 !csum_tcpudp_magic(iph->saddr, iph->daddr,
176 skb->len - dataoff, protocol,
177 skb->csum)) {
178 skb->ip_summed = CHECKSUM_UNNECESSARY;
179 break;
180 }
181 /* fall through */
182 case CHECKSUM_NONE:
183 if (protocol == 0)
184 skb->csum = 0;
185 else
186 skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
187 skb->len - dataoff,
188 protocol, 0);
189 csum = __skb_checksum_complete(skb);
190 }
191 return csum;
192}
193
194EXPORT_SYMBOL(nf_ip_checksum);
195
164static struct nf_afinfo nf_ip_afinfo = { 196static struct nf_afinfo nf_ip_afinfo = {
165 .family = AF_INET, 197 .family = AF_INET,
198 .checksum = nf_ip_checksum,
166 .saveroute = nf_ip_saveroute, 199 .saveroute = nf_ip_saveroute,
167 .reroute = nf_ip_reroute, 200 .reroute = nf_ip_reroute,
168 .route_key_size = sizeof(struct ip_rt_info), 201 .route_key_size = sizeof(struct ip_rt_info),
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index f514a0113b9f..3e9ecfaf67e2 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -79,8 +79,42 @@ static int nf_ip6_reroute(struct sk_buff **pskb, const struct nf_info *info)
79 return 0; 79 return 0;
80} 80}
81 81
82unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
83 unsigned int dataoff, u_int8_t protocol)
84{
85 struct ipv6hdr *ip6h = skb->nh.ipv6h;
86 unsigned int csum = 0;
87
88 switch (skb->ip_summed) {
89 case CHECKSUM_HW:
90 if (hook != NF_IP6_PRE_ROUTING && hook != NF_IP6_LOCAL_IN)
91 break;
92 if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
93 skb->len - dataoff, protocol,
94 csum_sub(skb->csum,
95 skb_checksum(skb, 0,
96 dataoff, 0)))) {
97 skb->ip_summed = CHECKSUM_UNNECESSARY;
98 break;
99 }
100 /* fall through */
101 case CHECKSUM_NONE:
102 skb->csum = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
103 skb->len - dataoff,
104 protocol,
105 csum_sub(0,
106 skb_checksum(skb, 0,
107 dataoff, 0)));
108 csum = __skb_checksum_complete(skb);
109 }
110 return csum;
111}
112
113EXPORT_SYMBOL(nf_ip6_checksum);
114
82static struct nf_afinfo nf_ip6_afinfo = { 115static struct nf_afinfo nf_ip6_afinfo = {
83 .family = AF_INET6, 116 .family = AF_INET6,
117 .checksum = nf_ip6_checksum,
84 .saveroute = nf_ip6_saveroute, 118 .saveroute = nf_ip6_saveroute,
85 .reroute = nf_ip6_reroute, 119 .reroute = nf_ip6_reroute,
86 .route_key_size = sizeof(struct ip6_rt_info), 120 .route_key_size = sizeof(struct ip6_rt_info),