aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/linux/netfilter.h17
-rw-r--r--include/linux/netfilter_ipv4.h2
-rw-r--r--include/linux/netfilter_ipv6.h3
-rw-r--r--net/ipv4/netfilter.c33
-rw-r--r--net/ipv6/netfilter.c34
5 files changed, 89 insertions, 0 deletions
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 6ee168c4978a..b31a9bca9361 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -285,6 +285,8 @@ extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len);
285 285
286struct nf_afinfo { 286struct nf_afinfo {
287 unsigned short family; 287 unsigned short family;
288 unsigned int (*checksum)(struct sk_buff *skb, unsigned int hook,
289 unsigned int dataoff, u_int8_t protocol);
288 void (*saveroute)(const struct sk_buff *skb, 290 void (*saveroute)(const struct sk_buff *skb,
289 struct nf_info *info); 291 struct nf_info *info);
290 int (*reroute)(struct sk_buff **skb, 292 int (*reroute)(struct sk_buff **skb,
@@ -298,6 +300,21 @@ static inline struct nf_afinfo *nf_get_afinfo(unsigned short family)
298 return rcu_dereference(nf_afinfo[family]); 300 return rcu_dereference(nf_afinfo[family]);
299} 301}
300 302
303static inline unsigned int
304nf_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff,
305 u_int8_t protocol, unsigned short family)
306{
307 struct nf_afinfo *afinfo;
308 unsigned int csum = 0;
309
310 rcu_read_lock();
311 afinfo = nf_get_afinfo(family);
312 if (afinfo)
313 csum = afinfo->checksum(skb, hook, dataoff, protocol);
314 rcu_read_unlock();
315 return csum;
316}
317
301extern int nf_register_afinfo(struct nf_afinfo *afinfo); 318extern int nf_register_afinfo(struct nf_afinfo *afinfo);
302extern void nf_unregister_afinfo(struct nf_afinfo *afinfo); 319extern void nf_unregister_afinfo(struct nf_afinfo *afinfo);
303 320
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
index 43c09d790b83..85301c5e8d24 100644
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -80,6 +80,8 @@ enum nf_ip_hook_priorities {
80#ifdef __KERNEL__ 80#ifdef __KERNEL__
81extern int ip_route_me_harder(struct sk_buff **pskb); 81extern int ip_route_me_harder(struct sk_buff **pskb);
82extern int ip_xfrm_me_harder(struct sk_buff **pskb); 82extern int ip_xfrm_me_harder(struct sk_buff **pskb);
83extern unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
84 unsigned int dataoff, u_int8_t protocol);
83#endif /*__KERNEL__*/ 85#endif /*__KERNEL__*/
84 86
85#endif /*__LINUX_IP_NETFILTER_H*/ 87#endif /*__LINUX_IP_NETFILTER_H*/
diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h
index 14f2bd010884..52a7b9e76428 100644
--- a/include/linux/netfilter_ipv6.h
+++ b/include/linux/netfilter_ipv6.h
@@ -73,6 +73,9 @@ enum nf_ip6_hook_priorities {
73}; 73};
74 74
75#ifdef CONFIG_NETFILTER 75#ifdef CONFIG_NETFILTER
76extern unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
77 unsigned int dataoff, u_int8_t protocol);
78
76extern int ipv6_netfilter_init(void); 79extern int ipv6_netfilter_init(void);
77extern void ipv6_netfilter_fini(void); 80extern void ipv6_netfilter_fini(void);
78#else /* CONFIG_NETFILTER */ 81#else /* CONFIG_NETFILTER */
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),