diff options
Diffstat (limited to 'net/dccp/ipv6.c')
-rw-r--r-- | net/dccp/ipv6.c | 74 |
1 files changed, 47 insertions, 27 deletions
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 | ||