diff options
Diffstat (limited to 'net/dccp/ipv4.c')
-rw-r--r-- | net/dccp/ipv4.c | 105 |
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. */ | 352 | static inline u16 dccp_v4_csum_finish(struct sk_buff *skb, |
353 | void 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 | |||
358 | void 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 | ||
361 | EXPORT_SYMBOL_GPL(dccp_v4_send_check); | 367 | EXPORT_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 | ||
457 | int 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 | |||
477 | EXPORT_SYMBOL_GPL(dccp_v4_checksum); | ||
478 | |||
479 | static 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 | |||
498 | static struct dst_entry* dccp_v4_route_skb(struct sock *sk, | 463 | static 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); | |||
779 | int dccp_invalid_packet(struct sk_buff *skb) | 745 | int 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); |