aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-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);