aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp
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
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')
-rw-r--r--net/dccp/dccp.h29
-rw-r--r--net/dccp/ipv4.c105
-rw-r--r--net/dccp/ipv6.c74
-rw-r--r--net/dccp/output.c13
-rw-r--r--net/dccp/proto.c26
5 files changed, 150 insertions, 97 deletions
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index 2990bfb12587..d5c414bf7819 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -129,6 +129,30 @@ DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics);
129#define DCCP_ADD_STATS_USER(field, val) \ 129#define DCCP_ADD_STATS_USER(field, val) \
130 SNMP_ADD_STATS_USER(dccp_statistics, field, val) 130 SNMP_ADD_STATS_USER(dccp_statistics, field, val)
131 131
132/*
133 * Checksumming routines
134 */
135static inline int dccp_csum_coverage(const struct sk_buff *skb)
136{
137 const struct dccp_hdr* dh = dccp_hdr(skb);
138
139 if (dh->dccph_cscov == 0)
140 return skb->len;
141 return (dh->dccph_doff + dh->dccph_cscov - 1) * sizeof(u32);
142}
143
144static inline void dccp_csum_outgoing(struct sk_buff *skb)
145{
146 int cov = dccp_csum_coverage(skb);
147
148 if (cov >= skb->len)
149 dccp_hdr(skb)->dccph_cscov = 0;
150
151 skb->csum = skb_checksum(skb, 0, (cov > skb->len)? skb->len : cov, 0);
152}
153
154extern void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb);
155
132extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb); 156extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb);
133 157
134extern void dccp_send_ack(struct sock *sk); 158extern void dccp_send_ack(struct sock *sk);
@@ -214,14 +238,9 @@ extern void dccp_shutdown(struct sock *sk, int how);
214extern int inet_dccp_listen(struct socket *sock, int backlog); 238extern int inet_dccp_listen(struct socket *sock, int backlog);
215extern unsigned int dccp_poll(struct file *file, struct socket *sock, 239extern unsigned int dccp_poll(struct file *file, struct socket *sock,
216 poll_table *wait); 240 poll_table *wait);
217extern void dccp_v4_send_check(struct sock *sk, int len,
218 struct sk_buff *skb);
219extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, 241extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
220 int addr_len); 242 int addr_len);
221 243
222extern int dccp_v4_checksum(const struct sk_buff *skb,
223 const __be32 saddr, const __be32 daddr);
224
225extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code); 244extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code);
226extern void dccp_send_close(struct sock *sk, const int active); 245extern void dccp_send_close(struct sock *sk, const int active);
227extern int dccp_invalid_packet(struct sk_buff *skb); 246extern int dccp_invalid_packet(struct sk_buff *skb);
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);
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
diff --git a/net/dccp/output.c b/net/dccp/output.c
index 51654975e8ea..992caedd7725 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -96,6 +96,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
96 dh->dccph_dport = inet->dport; 96 dh->dccph_dport = inet->dport;
97 dh->dccph_doff = (dccp_header_size + dcb->dccpd_opt_len) / 4; 97 dh->dccph_doff = (dccp_header_size + dcb->dccpd_opt_len) / 4;
98 dh->dccph_ccval = dcb->dccpd_ccval; 98 dh->dccph_ccval = dcb->dccpd_ccval;
99 dh->dccph_cscov = dp->dccps_pcslen;
99 /* XXX For now we're using only 48 bits sequence numbers */ 100 /* XXX For now we're using only 48 bits sequence numbers */
100 dh->dccph_x = 1; 101 dh->dccph_x = 1;
101 102
@@ -115,7 +116,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
115 break; 116 break;
116 } 117 }
117 118
118 icsk->icsk_af_ops->send_check(sk, skb->len, skb); 119 icsk->icsk_af_ops->send_check(sk, 0, skb);
119 120
120 if (set_ack) 121 if (set_ack)
121 dccp_event_ack_sent(sk); 122 dccp_event_ack_sent(sk);
@@ -329,7 +330,6 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
329 skb_reserve(skb, sk->sk_prot->max_header); 330 skb_reserve(skb, sk->sk_prot->max_header);
330 331
331 skb->dst = dst_clone(dst); 332 skb->dst = dst_clone(dst);
332 skb->csum = 0;
333 333
334 dreq = dccp_rsk(req); 334 dreq = dccp_rsk(req);
335 DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE; 335 DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE;
@@ -352,6 +352,8 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
352 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_isr); 352 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_isr);
353 dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service; 353 dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service;
354 354
355 dccp_csum_outgoing(skb);
356
355 DCCP_INC_STATS(DCCP_MIB_OUTSEGS); 357 DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
356 return skb; 358 return skb;
357} 359}
@@ -376,7 +378,6 @@ static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
376 skb_reserve(skb, sk->sk_prot->max_header); 378 skb_reserve(skb, sk->sk_prot->max_header);
377 379
378 skb->dst = dst_clone(dst); 380 skb->dst = dst_clone(dst);
379 skb->csum = 0;
380 381
381 dccp_inc_seqno(&dp->dccps_gss); 382 dccp_inc_seqno(&dp->dccps_gss);
382 383
@@ -401,7 +402,7 @@ static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
401 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dp->dccps_gsr); 402 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dp->dccps_gsr);
402 403
403 dccp_hdr_reset(skb)->dccph_reset_code = code; 404 dccp_hdr_reset(skb)->dccph_reset_code = code;
404 inet_csk(sk)->icsk_af_ops->send_check(sk, skb->len, skb); 405 inet_csk(sk)->icsk_af_ops->send_check(sk, 0, skb);
405 406
406 DCCP_INC_STATS(DCCP_MIB_OUTSEGS); 407 DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
407 return skb; 408 return skb;
@@ -475,7 +476,6 @@ int dccp_connect(struct sock *sk)
475 skb_reserve(skb, sk->sk_prot->max_header); 476 skb_reserve(skb, sk->sk_prot->max_header);
476 477
477 DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST; 478 DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST;
478 skb->csum = 0;
479 479
480 dccp_skb_entail(sk, skb); 480 dccp_skb_entail(sk, skb);
481 dccp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL)); 481 dccp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL));
@@ -507,7 +507,6 @@ void dccp_send_ack(struct sock *sk)
507 507
508 /* Reserve space for headers */ 508 /* Reserve space for headers */
509 skb_reserve(skb, sk->sk_prot->max_header); 509 skb_reserve(skb, sk->sk_prot->max_header);
510 skb->csum = 0;
511 DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_ACK; 510 DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_ACK;
512 dccp_transmit_skb(sk, skb); 511 dccp_transmit_skb(sk, skb);
513 } 512 }
@@ -561,7 +560,6 @@ void dccp_send_sync(struct sock *sk, const u64 seq,
561 560
562 /* Reserve space for headers and prepare control bits. */ 561 /* Reserve space for headers and prepare control bits. */
563 skb_reserve(skb, sk->sk_prot->max_header); 562 skb_reserve(skb, sk->sk_prot->max_header);
564 skb->csum = 0;
565 DCCP_SKB_CB(skb)->dccpd_type = pkt_type; 563 DCCP_SKB_CB(skb)->dccpd_type = pkt_type;
566 DCCP_SKB_CB(skb)->dccpd_seq = seq; 564 DCCP_SKB_CB(skb)->dccpd_seq = seq;
567 565
@@ -587,7 +585,6 @@ void dccp_send_close(struct sock *sk, const int active)
587 585
588 /* Reserve space for headers and prepare control bits. */ 586 /* Reserve space for headers and prepare control bits. */
589 skb_reserve(skb, sk->sk_prot->max_header); 587 skb_reserve(skb, sk->sk_prot->max_header);
590 skb->csum = 0;
591 DCCP_SKB_CB(skb)->dccpd_type = dp->dccps_role == DCCP_ROLE_CLIENT ? 588 DCCP_SKB_CB(skb)->dccpd_type = dp->dccps_role == DCCP_ROLE_CLIENT ?
592 DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ; 589 DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ;
593 590
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 047d170a363a..db54e557eff1 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -472,7 +472,6 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
472 case DCCP_SOCKOPT_PACKET_SIZE: 472 case DCCP_SOCKOPT_PACKET_SIZE:
473 dp->dccps_packet_size = val; 473 dp->dccps_packet_size = val;
474 break; 474 break;
475
476 case DCCP_SOCKOPT_CHANGE_L: 475 case DCCP_SOCKOPT_CHANGE_L:
477 if (optlen != sizeof(struct dccp_so_feat)) 476 if (optlen != sizeof(struct dccp_so_feat))
478 err = -EINVAL; 477 err = -EINVAL;
@@ -481,7 +480,6 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
481 (struct dccp_so_feat __user *) 480 (struct dccp_so_feat __user *)
482 optval); 481 optval);
483 break; 482 break;
484
485 case DCCP_SOCKOPT_CHANGE_R: 483 case DCCP_SOCKOPT_CHANGE_R:
486 if (optlen != sizeof(struct dccp_so_feat)) 484 if (optlen != sizeof(struct dccp_so_feat))
487 err = -EINVAL; 485 err = -EINVAL;
@@ -490,12 +488,26 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
490 (struct dccp_so_feat __user *) 488 (struct dccp_so_feat __user *)
491 optval); 489 optval);
492 break; 490 break;
493 491 case DCCP_SOCKOPT_SEND_CSCOV: /* sender side, RFC 4340, sec. 9.2 */
492 if (val < 0 || val > 15)
493 err = -EINVAL;
494 else
495 dp->dccps_pcslen = val;
496 break;
497 case DCCP_SOCKOPT_RECV_CSCOV: /* receiver side, RFC 4340 sec. 9.2.1 */
498 if (val < 0 || val > 15)
499 err = -EINVAL;
500 else {
501 dp->dccps_pcrlen = val;
502 /* FIXME: add feature negotiation,
503 * ChangeL(MinimumChecksumCoverage, val) */
504 }
505 break;
494 default: 506 default:
495 err = -ENOPROTOOPT; 507 err = -ENOPROTOOPT;
496 break; 508 break;
497 } 509 }
498 510
499 release_sock(sk); 511 release_sock(sk);
500 return err; 512 return err;
501} 513}
@@ -575,6 +587,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
575 case DCCP_SOCKOPT_SERVICE: 587 case DCCP_SOCKOPT_SERVICE:
576 return dccp_getsockopt_service(sk, len, 588 return dccp_getsockopt_service(sk, len,
577 (__be32 __user *)optval, optlen); 589 (__be32 __user *)optval, optlen);
590 case DCCP_SOCKOPT_SEND_CSCOV:
591 val = dp->dccps_pcslen;
592 break;
593 case DCCP_SOCKOPT_RECV_CSCOV:
594 val = dp->dccps_pcrlen;
595 break;
578 case 128 ... 191: 596 case 128 ... 191:
579 return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, 597 return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
580 len, (u32 __user *)optval, optlen); 598 len, (u32 __user *)optval, optlen);