diff options
Diffstat (limited to 'net/ipv6/icmp.c')
-rw-r--r-- | net/ipv6/icmp.c | 41 |
1 files changed, 13 insertions, 28 deletions
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 7b326529e6a2..f6c84a6eb238 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -400,6 +400,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
400 | int len; | 400 | int len; |
401 | int hlimit; | 401 | int hlimit; |
402 | int err = 0; | 402 | int err = 0; |
403 | u32 mark = IP6_REPLY_MARK(net, skb->mark); | ||
403 | 404 | ||
404 | if ((u8 *)hdr < skb->head || | 405 | if ((u8 *)hdr < skb->head || |
405 | (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb)) | 406 | (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb)) |
@@ -466,6 +467,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
466 | fl6.daddr = hdr->saddr; | 467 | fl6.daddr = hdr->saddr; |
467 | if (saddr) | 468 | if (saddr) |
468 | fl6.saddr = *saddr; | 469 | fl6.saddr = *saddr; |
470 | fl6.flowi6_mark = mark; | ||
469 | fl6.flowi6_oif = iif; | 471 | fl6.flowi6_oif = iif; |
470 | fl6.fl6_icmp_type = type; | 472 | fl6.fl6_icmp_type = type; |
471 | fl6.fl6_icmp_code = code; | 473 | fl6.fl6_icmp_code = code; |
@@ -474,6 +476,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
474 | sk = icmpv6_xmit_lock(net); | 476 | sk = icmpv6_xmit_lock(net); |
475 | if (sk == NULL) | 477 | if (sk == NULL) |
476 | return; | 478 | return; |
479 | sk->sk_mark = mark; | ||
477 | np = inet6_sk(sk); | 480 | np = inet6_sk(sk); |
478 | 481 | ||
479 | if (!icmpv6_xrlim_allow(sk, type, &fl6)) | 482 | if (!icmpv6_xrlim_allow(sk, type, &fl6)) |
@@ -493,12 +496,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
493 | if (IS_ERR(dst)) | 496 | if (IS_ERR(dst)) |
494 | goto out; | 497 | goto out; |
495 | 498 | ||
496 | if (ipv6_addr_is_multicast(&fl6.daddr)) | 499 | hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); |
497 | hlimit = np->mcast_hops; | ||
498 | else | ||
499 | hlimit = np->hop_limit; | ||
500 | if (hlimit < 0) | ||
501 | hlimit = ip6_dst_hoplimit(dst); | ||
502 | 500 | ||
503 | msg.skb = skb; | 501 | msg.skb = skb; |
504 | msg.offset = skb_network_offset(skb); | 502 | msg.offset = skb_network_offset(skb); |
@@ -556,6 +554,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
556 | int err = 0; | 554 | int err = 0; |
557 | int hlimit; | 555 | int hlimit; |
558 | u8 tclass; | 556 | u8 tclass; |
557 | u32 mark = IP6_REPLY_MARK(net, skb->mark); | ||
559 | 558 | ||
560 | saddr = &ipv6_hdr(skb)->daddr; | 559 | saddr = &ipv6_hdr(skb)->daddr; |
561 | 560 | ||
@@ -574,11 +573,13 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
574 | fl6.saddr = *saddr; | 573 | fl6.saddr = *saddr; |
575 | fl6.flowi6_oif = skb->dev->ifindex; | 574 | fl6.flowi6_oif = skb->dev->ifindex; |
576 | fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY; | 575 | fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY; |
576 | fl6.flowi6_mark = mark; | ||
577 | security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); | 577 | security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); |
578 | 578 | ||
579 | sk = icmpv6_xmit_lock(net); | 579 | sk = icmpv6_xmit_lock(net); |
580 | if (sk == NULL) | 580 | if (sk == NULL) |
581 | return; | 581 | return; |
582 | sk->sk_mark = mark; | ||
582 | np = inet6_sk(sk); | 583 | np = inet6_sk(sk); |
583 | 584 | ||
584 | if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) | 585 | if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) |
@@ -593,12 +594,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
593 | if (IS_ERR(dst)) | 594 | if (IS_ERR(dst)) |
594 | goto out; | 595 | goto out; |
595 | 596 | ||
596 | if (ipv6_addr_is_multicast(&fl6.daddr)) | 597 | hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); |
597 | hlimit = np->mcast_hops; | ||
598 | else | ||
599 | hlimit = np->hop_limit; | ||
600 | if (hlimit < 0) | ||
601 | hlimit = ip6_dst_hoplimit(dst); | ||
602 | 598 | ||
603 | idev = __in6_dev_get(skb->dev); | 599 | idev = __in6_dev_get(skb->dev); |
604 | 600 | ||
@@ -702,22 +698,11 @@ static int icmpv6_rcv(struct sk_buff *skb) | |||
702 | saddr = &ipv6_hdr(skb)->saddr; | 698 | saddr = &ipv6_hdr(skb)->saddr; |
703 | daddr = &ipv6_hdr(skb)->daddr; | 699 | daddr = &ipv6_hdr(skb)->daddr; |
704 | 700 | ||
705 | /* Perform checksum. */ | 701 | if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) { |
706 | switch (skb->ip_summed) { | 702 | LIMIT_NETDEBUG(KERN_DEBUG |
707 | case CHECKSUM_COMPLETE: | 703 | "ICMPv6 checksum failed [%pI6c > %pI6c]\n", |
708 | if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, | 704 | saddr, daddr); |
709 | skb->csum)) | 705 | goto csum_error; |
710 | break; | ||
711 | /* fall through */ | ||
712 | case CHECKSUM_NONE: | ||
713 | skb->csum = ~csum_unfold(csum_ipv6_magic(saddr, daddr, skb->len, | ||
714 | IPPROTO_ICMPV6, 0)); | ||
715 | if (__skb_checksum_complete(skb)) { | ||
716 | LIMIT_NETDEBUG(KERN_DEBUG | ||
717 | "ICMPv6 checksum failed [%pI6c > %pI6c]\n", | ||
718 | saddr, daddr); | ||
719 | goto csum_error; | ||
720 | } | ||
721 | } | 706 | } |
722 | 707 | ||
723 | if (!pskb_pull(skb, sizeof(*hdr))) | 708 | if (!pskb_pull(skb, sizeof(*hdr))) |