aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/ipv6.c
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2006-11-10 14:43:06 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-03 00:22:09 -0500
commit6f4e5fff1e4d46714ea554fd83e44eab534e8b11 (patch)
tree4b14344fd825bbcefb6e8514e98e3e796b2dc1bd /net/dccp/ipv6.c
parenta11d206d0f88e092419877c7f706cafb5e1c2e57 (diff)
[DCCP]: Support for partial checksums (RFC 4340, sec. 9.2)
This patch does the following: a) introduces variable-length checksums as specified in [RFC 4340, sec. 9.2] b) provides necessary socket options and documentation as to how to use them c) basic support and infrastructure for the Minimum Checksum Coverage feature [RFC 4340, sec. 9.2.1]: acceptability tests, user notification and user interface In addition, it (1) fixes two bugs in the DCCPv4 checksum computation: * pseudo-header used checksum_len instead of skb->len * incorrect checksum coverage calculation based on dccph_x (2) removes dccp_v4_verify_checksum() since it reduplicates code of the checksum computation; code calling this function is updated accordingly. (3) now uses skb_checksum(), which is safer than checksum_partial() if the sk_buff has is a non-linear buffer (has pages attached to it). (4) fixes an outstanding TODO item: * If P.CsCov is too large for the packet size, drop packet and return. The code has been tested with applications, the latest version of tcpdump now comes with support for partial DCCP checksums. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Diffstat (limited to 'net/dccp/ipv6.c')
-rw-r--r--net/dccp/ipv6.c74
1 files changed, 47 insertions, 27 deletions
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 201801e1532d..193b946fd039 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -58,12 +58,22 @@ static void dccp_v6_hash(struct sock *sk)
58 } 58 }
59} 59}
60 60
61static inline u16 dccp_v6_check(struct dccp_hdr *dh, int len, 61/* add pseudo-header to DCCP checksum stored in skb->csum */
62 struct in6_addr *saddr, 62static inline u16 dccp_v6_csum_finish(struct sk_buff *skb,
63 struct in6_addr *daddr, 63 struct in6_addr *saddr,
64 unsigned long base) 64 struct in6_addr *daddr)
65{ 65{
66 return csum_ipv6_magic(saddr, daddr, len, IPPROTO_DCCP, base); 66 return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
67}
68
69static inline void dccp_v6_send_check(struct sock *sk, int unused_value,
70 struct sk_buff *skb)
71{
72 struct ipv6_pinfo *np = inet6_sk(sk);
73 struct dccp_hdr *dh = dccp_hdr(skb);
74
75 dccp_csum_outgoing(skb);
76 dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &np->daddr);
67} 77}
68 78
69static __u32 dccp_v6_init_sequence(struct sock *sk, struct sk_buff *skb) 79static __u32 dccp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
@@ -280,12 +290,9 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
280 if (skb != NULL) { 290 if (skb != NULL) {
281 struct dccp_hdr *dh = dccp_hdr(skb); 291 struct dccp_hdr *dh = dccp_hdr(skb);
282 292
283 dh->dccph_checksum = dccp_v6_check(dh, skb->len, 293 dh->dccph_checksum = dccp_v6_csum_finish(skb,
284 &ireq6->loc_addr, 294 &ireq6->loc_addr,
285 &ireq6->rmt_addr, 295 &ireq6->rmt_addr);
286 csum_partial((char *)dh,
287 skb->len,
288 skb->csum));
289 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); 296 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
290 err = ip6_xmit(sk, skb, &fl, opt, 0); 297 err = ip6_xmit(sk, skb, &fl, opt, 0);
291 if (err == NET_XMIT_CN) 298 if (err == NET_XMIT_CN)
@@ -305,18 +312,6 @@ static void dccp_v6_reqsk_destructor(struct request_sock *req)
305 kfree_skb(inet6_rsk(req)->pktopts); 312 kfree_skb(inet6_rsk(req)->pktopts);
306} 313}
307 314
308static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
309{
310 struct ipv6_pinfo *np = inet6_sk(sk);
311 struct dccp_hdr *dh = dccp_hdr(skb);
312
313 dh->dccph_checksum = csum_ipv6_magic(&np->saddr, &np->daddr,
314 len, IPPROTO_DCCP,
315 csum_partial((char *)dh,
316 dh->dccph_doff << 2,
317 skb->csum));
318}
319
320static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) 315static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb)
321{ 316{
322 struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; 317 struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
@@ -360,12 +355,14 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb)
360 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), 355 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb),
361 DCCP_SKB_CB(rxskb)->dccpd_seq); 356 DCCP_SKB_CB(rxskb)->dccpd_seq);
362 357
358 dccp_csum_outgoing(skb);
359 dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxskb->nh.ipv6h->saddr,
360 &rxskb->nh.ipv6h->daddr);
361
363 memset(&fl, 0, sizeof(fl)); 362 memset(&fl, 0, sizeof(fl));
364 ipv6_addr_copy(&fl.fl6_dst, &rxskb->nh.ipv6h->saddr); 363 ipv6_addr_copy(&fl.fl6_dst, &rxskb->nh.ipv6h->saddr);
365 ipv6_addr_copy(&fl.fl6_src, &rxskb->nh.ipv6h->daddr); 364 ipv6_addr_copy(&fl.fl6_src, &rxskb->nh.ipv6h->daddr);
366 dh->dccph_checksum = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst, 365
367 sizeof(*dh), IPPROTO_DCCP,
368 skb->csum);
369 fl.proto = IPPROTO_DCCP; 366 fl.proto = IPPROTO_DCCP;
370 fl.oif = inet6_iif(rxskb); 367 fl.oif = inet6_iif(rxskb);
371 fl.fl_ip_dport = dh->dccph_dport; 368 fl.fl_ip_dport = dh->dccph_dport;
@@ -825,12 +822,22 @@ static int dccp_v6_rcv(struct sk_buff **pskb)
825 const struct dccp_hdr *dh; 822 const struct dccp_hdr *dh;
826 struct sk_buff *skb = *pskb; 823 struct sk_buff *skb = *pskb;
827 struct sock *sk; 824 struct sock *sk;
825 int min_cov;
828 826
829 /* Step 1: Check header basics: */ 827 /* Step 1: Check header basics */
830 828
831 if (dccp_invalid_packet(skb)) 829 if (dccp_invalid_packet(skb))
832 goto discard_it; 830 goto discard_it;
833 831
832 /* Step 1: If header checksum is incorrect, drop packet and return. */
833 if (dccp_v6_csum_finish(skb, &skb->nh.ipv6h->saddr,
834 &skb->nh.ipv6h->daddr)) {
835 LIMIT_NETDEBUG(KERN_WARNING
836 "%s: dropped packet with invalid checksum\n",
837 __FUNCTION__);
838 goto discard_it;
839 }
840
834 dh = dccp_hdr(skb); 841 dh = dccp_hdr(skb);
835 842
836 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb); 843 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb);
@@ -869,6 +876,19 @@ static int dccp_v6_rcv(struct sk_buff **pskb)
869 goto no_dccp_socket; 876 goto no_dccp_socket;
870 } 877 }
871 878
879 /*
880 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
881 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
882 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
883 */
884 min_cov = dccp_sk(sk)->dccps_pcrlen;
885 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
886 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
887 dh->dccph_cscov, min_cov);
888 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
889 goto discard_and_relse;
890 }
891
872 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) 892 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
873 goto discard_and_relse; 893 goto discard_and_relse;
874 894