diff options
-rw-r--r-- | Documentation/networking/dccp.txt | 16 | ||||
-rw-r--r-- | include/linux/dccp.h | 7 | ||||
-rw-r--r-- | net/dccp/dccp.h | 29 | ||||
-rw-r--r-- | net/dccp/ipv4.c | 105 | ||||
-rw-r--r-- | net/dccp/ipv6.c | 74 | ||||
-rw-r--r-- | net/dccp/output.c | 13 | ||||
-rw-r--r-- | net/dccp/proto.c | 26 |
7 files changed, 173 insertions, 97 deletions
diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index 74563b38ffd9..a8142a81038a 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt | |||
@@ -47,6 +47,22 @@ the socket will fall back to 0 (which means that no meaningful service code | |||
47 | is present). Connecting sockets set at most one service option; for | 47 | is present). Connecting sockets set at most one service option; for |
48 | listening sockets, multiple service codes can be specified. | 48 | listening sockets, multiple service codes can be specified. |
49 | 49 | ||
50 | DCCP_SOCKOPT_SEND_CSCOV and DCCP_SOCKOPT_RECV_CSCOV are used for setting the | ||
51 | partial checksum coverage (RFC 4340, sec. 9.2). The default is that checksums | ||
52 | always cover the entire packet and that only fully covered application data is | ||
53 | accepted by the receiver. Hence, when using this feature on the sender, it must | ||
54 | be enabled at the receiver, too with suitable choice of CsCov. | ||
55 | |||
56 | DCCP_SOCKOPT_SEND_CSCOV sets the sender checksum coverage. Values in the | ||
57 | range 0..15 are acceptable. The default setting is 0 (full coverage), | ||
58 | values between 1..15 indicate partial coverage. | ||
59 | DCCP_SOCKOPT_SEND_CSCOV is for the receiver and has a different meaning: it | ||
60 | sets a threshold, where again values 0..15 are acceptable. The default | ||
61 | of 0 means that all packets with a partial coverage will be discarded. | ||
62 | Values in the range 1..15 indicate that packets with minimally such a | ||
63 | coverage value are also acceptable. The higher the number, the more | ||
64 | restrictive this setting (see [RFC 4340, sec. 9.2.1]). | ||
65 | |||
50 | Notes | 66 | Notes |
51 | ===== | 67 | ===== |
52 | 68 | ||
diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 90d04ffddae8..0502dfa7f32c 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h | |||
@@ -183,6 +183,7 @@ enum { | |||
183 | DCCPF_ACK_RATIO = 5, | 183 | DCCPF_ACK_RATIO = 5, |
184 | DCCPF_SEND_ACK_VECTOR = 6, | 184 | DCCPF_SEND_ACK_VECTOR = 6, |
185 | DCCPF_SEND_NDP_COUNT = 7, | 185 | DCCPF_SEND_NDP_COUNT = 7, |
186 | DCCPF_MIN_CSUM_COVER = 8, | ||
186 | /* 10-127 reserved */ | 187 | /* 10-127 reserved */ |
187 | DCCPF_MIN_CCID_SPECIFIC = 128, | 188 | DCCPF_MIN_CCID_SPECIFIC = 128, |
188 | DCCPF_MAX_CCID_SPECIFIC = 255, | 189 | DCCPF_MAX_CCID_SPECIFIC = 255, |
@@ -200,6 +201,8 @@ struct dccp_so_feat { | |||
200 | #define DCCP_SOCKOPT_SERVICE 2 | 201 | #define DCCP_SOCKOPT_SERVICE 2 |
201 | #define DCCP_SOCKOPT_CHANGE_L 3 | 202 | #define DCCP_SOCKOPT_CHANGE_L 3 |
202 | #define DCCP_SOCKOPT_CHANGE_R 4 | 203 | #define DCCP_SOCKOPT_CHANGE_R 4 |
204 | #define DCCP_SOCKOPT_SEND_CSCOV 10 | ||
205 | #define DCCP_SOCKOPT_RECV_CSCOV 11 | ||
203 | #define DCCP_SOCKOPT_CCID_RX_INFO 128 | 206 | #define DCCP_SOCKOPT_CCID_RX_INFO 128 |
204 | #define DCCP_SOCKOPT_CCID_TX_INFO 192 | 207 | #define DCCP_SOCKOPT_CCID_TX_INFO 192 |
205 | 208 | ||
@@ -450,6 +453,8 @@ struct dccp_ackvec; | |||
450 | * @dccps_timestamp_echo - latest timestamp received on a TIMESTAMP option | 453 | * @dccps_timestamp_echo - latest timestamp received on a TIMESTAMP option |
451 | * @dccps_packet_size - Set thru setsockopt | 454 | * @dccps_packet_size - Set thru setsockopt |
452 | * @dccps_role - Role of this sock, one of %dccp_role | 455 | * @dccps_role - Role of this sock, one of %dccp_role |
456 | * @dccps_pcslen - sender partial checksum coverage (via sockopt) | ||
457 | * @dccps_pcrlen - receiver partial checksum coverage (via sockopt) | ||
453 | * @dccps_ndp_count - number of Non Data Packets since last data packet | 458 | * @dccps_ndp_count - number of Non Data Packets since last data packet |
454 | * @dccps_hc_rx_ackvec - rx half connection ack vector | 459 | * @dccps_hc_rx_ackvec - rx half connection ack vector |
455 | * @dccps_xmit_timer - timer for when CCID is not ready to send | 460 | * @dccps_xmit_timer - timer for when CCID is not ready to send |
@@ -474,6 +479,8 @@ struct dccp_sock { | |||
474 | __u32 dccps_packet_size; | 479 | __u32 dccps_packet_size; |
475 | __u16 dccps_l_ack_ratio; | 480 | __u16 dccps_l_ack_ratio; |
476 | __u16 dccps_r_ack_ratio; | 481 | __u16 dccps_r_ack_ratio; |
482 | __u16 dccps_pcslen; | ||
483 | __u16 dccps_pcrlen; | ||
477 | unsigned long dccps_ndp_count; | 484 | unsigned long dccps_ndp_count; |
478 | __u32 dccps_mss_cache; | 485 | __u32 dccps_mss_cache; |
479 | struct dccp_minisock dccps_minisock; | 486 | struct dccp_minisock dccps_minisock; |
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 | */ | ||
135 | static 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 | |||
144 | static 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 | |||
154 | extern void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); | ||
155 | |||
132 | extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb); | 156 | extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb); |
133 | 157 | ||
134 | extern void dccp_send_ack(struct sock *sk); | 158 | extern void dccp_send_ack(struct sock *sk); |
@@ -214,14 +238,9 @@ extern void dccp_shutdown(struct sock *sk, int how); | |||
214 | extern int inet_dccp_listen(struct socket *sock, int backlog); | 238 | extern int inet_dccp_listen(struct socket *sock, int backlog); |
215 | extern unsigned int dccp_poll(struct file *file, struct socket *sock, | 239 | extern unsigned int dccp_poll(struct file *file, struct socket *sock, |
216 | poll_table *wait); | 240 | poll_table *wait); |
217 | extern void dccp_v4_send_check(struct sock *sk, int len, | ||
218 | struct sk_buff *skb); | ||
219 | extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, | 241 | extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, |
220 | int addr_len); | 242 | int addr_len); |
221 | 243 | ||
222 | extern int dccp_v4_checksum(const struct sk_buff *skb, | ||
223 | const __be32 saddr, const __be32 daddr); | ||
224 | |||
225 | extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code); | 244 | extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code); |
226 | extern void dccp_send_close(struct sock *sk, const int active); | 245 | extern void dccp_send_close(struct sock *sk, const int active); |
227 | extern int dccp_invalid_packet(struct sk_buff *skb); | 246 | extern 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. */ | 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); |
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 | ||
61 | static 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, | 62 | static 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 | |||
69 | static 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 | ||
69 | static __u32 dccp_v6_init_sequence(struct sock *sk, struct sk_buff *skb) | 79 | static __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 | ||
308 | static 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 | |||
320 | static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | 315 | static 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); |