aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/ipv4.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/ipv4.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/ipv4.c')
-rw-r--r--net/dccp/ipv4.c105
1 files changed, 52 insertions, 53 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 91bffaa761a6..496112080f3d 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -349,13 +349,19 @@ out:
349 sock_put(sk); 349 sock_put(sk);
350} 350}
351 351
352/* This routine computes an IPv4 DCCP checksum. */ 352static inline u16 dccp_v4_csum_finish(struct sk_buff *skb,
353void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) 353 __be32 src, __be32 dst)
354{
355 return csum_tcpudp_magic(src, dst, skb->len, IPPROTO_DCCP, skb->csum);
356}
357
358void dccp_v4_send_check(struct sock *sk, int unused, struct sk_buff *skb)
354{ 359{
355 const struct inet_sock *inet = inet_sk(sk); 360 const struct inet_sock *inet = inet_sk(sk);
356 struct dccp_hdr *dh = dccp_hdr(skb); 361 struct dccp_hdr *dh = dccp_hdr(skb);
357 362
358 dh->dccph_checksum = dccp_v4_checksum(skb, inet->saddr, inet->daddr); 363 dccp_csum_outgoing(skb);
364 dh->dccph_checksum = dccp_v4_csum_finish(skb, inet->saddr, inet->daddr);
359} 365}
360 366
361EXPORT_SYMBOL_GPL(dccp_v4_send_check); 367EXPORT_SYMBOL_GPL(dccp_v4_send_check);
@@ -454,47 +460,6 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
454 return sk; 460 return sk;
455} 461}
456 462
457int dccp_v4_checksum(const struct sk_buff *skb, const __be32 saddr,
458 const __be32 daddr)
459{
460 const struct dccp_hdr* dh = dccp_hdr(skb);
461 int checksum_len;
462 u32 tmp;
463
464 if (dh->dccph_cscov == 0)
465 checksum_len = skb->len;
466 else {
467 checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32);
468 checksum_len = checksum_len < skb->len ? checksum_len :
469 skb->len;
470 }
471
472 tmp = csum_partial((unsigned char *)dh, checksum_len, 0);
473 return csum_tcpudp_magic(saddr, daddr, checksum_len,
474 IPPROTO_DCCP, tmp);
475}
476
477EXPORT_SYMBOL_GPL(dccp_v4_checksum);
478
479static int dccp_v4_verify_checksum(struct sk_buff *skb,
480 const __be32 saddr, const __be32 daddr)
481{
482 struct dccp_hdr *dh = dccp_hdr(skb);
483 int checksum_len;
484 u32 tmp;
485
486 if (dh->dccph_cscov == 0)
487 checksum_len = skb->len;
488 else {
489 checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32);
490 checksum_len = checksum_len < skb->len ? checksum_len :
491 skb->len;
492 }
493 tmp = csum_partial((unsigned char *)dh, checksum_len, 0);
494 return csum_tcpudp_magic(saddr, daddr, checksum_len,
495 IPPROTO_DCCP, tmp) == 0 ? 0 : -1;
496}
497
498static struct dst_entry* dccp_v4_route_skb(struct sock *sk, 463static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
499 struct sk_buff *skb) 464 struct sk_buff *skb)
500{ 465{
@@ -536,8 +501,8 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
536 const struct inet_request_sock *ireq = inet_rsk(req); 501 const struct inet_request_sock *ireq = inet_rsk(req);
537 struct dccp_hdr *dh = dccp_hdr(skb); 502 struct dccp_hdr *dh = dccp_hdr(skb);
538 503
539 dh->dccph_checksum = dccp_v4_checksum(skb, ireq->loc_addr, 504 dh->dccph_checksum = dccp_v4_csum_finish(skb, ireq->loc_addr,
540 ireq->rmt_addr); 505 ireq->rmt_addr);
541 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); 506 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
542 err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, 507 err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr,
543 ireq->rmt_addr, 508 ireq->rmt_addr,
@@ -602,8 +567,9 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb)
602 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), 567 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb),
603 DCCP_SKB_CB(rxskb)->dccpd_seq); 568 DCCP_SKB_CB(rxskb)->dccpd_seq);
604 569
605 dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr, 570 dccp_csum_outgoing(skb);
606 rxskb->nh.iph->daddr); 571 dh->dccph_checksum = dccp_v4_csum_finish(skb, rxskb->nh.iph->saddr,
572 rxskb->nh.iph->daddr);
607 573
608 bh_lock_sock(dccp_v4_ctl_socket->sk); 574 bh_lock_sock(dccp_v4_ctl_socket->sk);
609 err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk, 575 err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk,
@@ -779,6 +745,7 @@ EXPORT_SYMBOL_GPL(dccp_v4_do_rcv);
779int dccp_invalid_packet(struct sk_buff *skb) 745int dccp_invalid_packet(struct sk_buff *skb)
780{ 746{
781 const struct dccp_hdr *dh; 747 const struct dccp_hdr *dh;
748 unsigned int cscov;
782 749
783 if (skb->pkt_type != PACKET_HOST) 750 if (skb->pkt_type != PACKET_HOST)
784 return 1; 751 return 1;
@@ -830,6 +797,22 @@ int dccp_invalid_packet(struct sk_buff *skb)
830 return 1; 797 return 1;
831 } 798 }
832 799
800 /*
801 * If P.CsCov is too large for the packet size, drop packet and return.
802 * This must come _before_ checksumming (not as RFC 4340 suggests).
803 */
804 cscov = dccp_csum_coverage(skb);
805 if (cscov > skb->len) {
806 LIMIT_NETDEBUG(KERN_WARNING
807 "DCCP: P.CsCov %u exceeds packet length %d\n",
808 dh->dccph_cscov, skb->len);
809 return 1;
810 }
811
812 /* If header checksum is incorrect, drop packet and return.
813 * (This step is completed in the AF-dependent functions.) */
814 skb->csum = skb_checksum(skb, 0, cscov, 0);
815
833 return 0; 816 return 0;
834} 817}
835 818
@@ -840,16 +823,17 @@ static int dccp_v4_rcv(struct sk_buff *skb)
840{ 823{
841 const struct dccp_hdr *dh; 824 const struct dccp_hdr *dh;
842 struct sock *sk; 825 struct sock *sk;
826 int min_cov;
843 827
844 /* Step 1: Check header basics: */ 828 /* Step 1: Check header basics */
845 829
846 if (dccp_invalid_packet(skb)) 830 if (dccp_invalid_packet(skb))
847 goto discard_it; 831 goto discard_it;
848 832
849 /* If the header checksum is incorrect, drop packet and return */ 833 /* Step 1: If header checksum is incorrect, drop packet and return */
850 if (dccp_v4_verify_checksum(skb, skb->nh.iph->saddr, 834 if (dccp_v4_csum_finish(skb, skb->nh.iph->saddr, skb->nh.iph->daddr)) {
851 skb->nh.iph->daddr) < 0) { 835 LIMIT_NETDEBUG(KERN_WARNING
852 LIMIT_NETDEBUG(KERN_WARNING "%s: incorrect header checksum\n", 836 "%s: dropped packet with invalid checksum\n",
853 __FUNCTION__); 837 __FUNCTION__);
854 goto discard_it; 838 goto discard_it;
855 } 839 }
@@ -905,6 +889,21 @@ static int dccp_v4_rcv(struct sk_buff *skb)
905 goto no_dccp_socket; 889 goto no_dccp_socket;
906 } 890 }
907 891
892 /*
893 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
894 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
895 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
896 */
897 min_cov = dccp_sk(sk)->dccps_pcrlen;
898 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
899 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
900 dh->dccph_cscov, min_cov);
901 /* FIXME: "Such packets SHOULD be reported using Data Dropped
902 * options (Section 11.7) with Drop Code 0, Protocol
903 * Constraints." */
904 goto discard_and_relse;
905 }
906
908 if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) 907 if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
909 goto discard_and_relse; 908 goto discard_and_relse;
910 nf_reset(skb); 909 nf_reset(skb);