diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
| -rw-r--r-- | net/ipv6/ip6_output.c | 129 |
1 files changed, 87 insertions, 42 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 3bc74ce78800..69451af6abe7 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
| @@ -356,6 +356,7 @@ int ip6_forward(struct sk_buff *skb) | |||
| 356 | skb->dev = dst->dev; | 356 | skb->dev = dst->dev; |
| 357 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, | 357 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, |
| 358 | 0, skb->dev); | 358 | 0, skb->dev); |
| 359 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
| 359 | 360 | ||
| 360 | kfree_skb(skb); | 361 | kfree_skb(skb); |
| 361 | return -ETIMEDOUT; | 362 | return -ETIMEDOUT; |
| @@ -595,6 +596,9 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 595 | } | 596 | } |
| 596 | 597 | ||
| 597 | err = output(skb); | 598 | err = output(skb); |
| 599 | if(!err) | ||
| 600 | IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); | ||
| 601 | |||
| 598 | if (err || !frag) | 602 | if (err || !frag) |
| 599 | break; | 603 | break; |
| 600 | 604 | ||
| @@ -706,12 +710,11 @@ slow_path: | |||
| 706 | /* | 710 | /* |
| 707 | * Put this fragment into the sending queue. | 711 | * Put this fragment into the sending queue. |
| 708 | */ | 712 | */ |
| 709 | |||
| 710 | IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); | ||
| 711 | |||
| 712 | err = output(frag); | 713 | err = output(frag); |
| 713 | if (err) | 714 | if (err) |
| 714 | goto fail; | 715 | goto fail; |
| 716 | |||
| 717 | IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); | ||
| 715 | } | 718 | } |
| 716 | kfree_skb(skb); | 719 | kfree_skb(skb); |
| 717 | IP6_INC_STATS(IPSTATS_MIB_FRAGOKS); | 720 | IP6_INC_STATS(IPSTATS_MIB_FRAGOKS); |
| @@ -723,48 +726,51 @@ fail: | |||
| 723 | return err; | 726 | return err; |
| 724 | } | 727 | } |
| 725 | 728 | ||
| 726 | int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | 729 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, |
| 730 | struct dst_entry *dst, | ||
| 731 | struct flowi *fl) | ||
| 727 | { | 732 | { |
| 728 | int err = 0; | 733 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 734 | struct rt6_info *rt = (struct rt6_info *)dst; | ||
| 729 | 735 | ||
| 730 | *dst = NULL; | 736 | if (!dst) |
| 731 | if (sk) { | 737 | goto out; |
| 732 | struct ipv6_pinfo *np = inet6_sk(sk); | 738 | |
| 733 | 739 | /* Yes, checking route validity in not connected | |
| 734 | *dst = sk_dst_check(sk, np->dst_cookie); | 740 | * case is not very simple. Take into account, |
| 735 | if (*dst) { | 741 | * that we do not support routing by source, TOS, |
| 736 | struct rt6_info *rt = (struct rt6_info*)*dst; | 742 | * and MSG_DONTROUTE --ANK (980726) |
| 737 | 743 | * | |
| 738 | /* Yes, checking route validity in not connected | 744 | * 1. If route was host route, check that |
| 739 | * case is not very simple. Take into account, | 745 | * cached destination is current. |
| 740 | * that we do not support routing by source, TOS, | 746 | * If it is network route, we still may |
| 741 | * and MSG_DONTROUTE --ANK (980726) | 747 | * check its validity using saved pointer |
| 742 | * | 748 | * to the last used address: daddr_cache. |
| 743 | * 1. If route was host route, check that | 749 | * We do not want to save whole address now, |
| 744 | * cached destination is current. | 750 | * (because main consumer of this service |
| 745 | * If it is network route, we still may | 751 | * is tcp, which has not this problem), |
| 746 | * check its validity using saved pointer | 752 | * so that the last trick works only on connected |
| 747 | * to the last used address: daddr_cache. | 753 | * sockets. |
| 748 | * We do not want to save whole address now, | 754 | * 2. oif also should be the same. |
| 749 | * (because main consumer of this service | 755 | */ |
| 750 | * is tcp, which has not this problem), | 756 | if (((rt->rt6i_dst.plen != 128 || |
| 751 | * so that the last trick works only on connected | 757 | !ipv6_addr_equal(&fl->fl6_dst, &rt->rt6i_dst.addr)) |
| 752 | * sockets. | 758 | && (np->daddr_cache == NULL || |
| 753 | * 2. oif also should be the same. | 759 | !ipv6_addr_equal(&fl->fl6_dst, np->daddr_cache))) |
| 754 | */ | 760 | || (fl->oif && fl->oif != dst->dev->ifindex)) { |
| 755 | if (((rt->rt6i_dst.plen != 128 || | 761 | dst_release(dst); |
| 756 | !ipv6_addr_equal(&fl->fl6_dst, | 762 | dst = NULL; |
| 757 | &rt->rt6i_dst.addr)) | ||
| 758 | && (np->daddr_cache == NULL || | ||
| 759 | !ipv6_addr_equal(&fl->fl6_dst, | ||
| 760 | np->daddr_cache))) | ||
| 761 | || (fl->oif && fl->oif != (*dst)->dev->ifindex)) { | ||
| 762 | dst_release(*dst); | ||
| 763 | *dst = NULL; | ||
| 764 | } | ||
| 765 | } | ||
| 766 | } | 763 | } |
| 767 | 764 | ||
| 765 | out: | ||
| 766 | return dst; | ||
| 767 | } | ||
| 768 | |||
| 769 | static int ip6_dst_lookup_tail(struct sock *sk, | ||
| 770 | struct dst_entry **dst, struct flowi *fl) | ||
| 771 | { | ||
| 772 | int err; | ||
| 773 | |||
| 768 | if (*dst == NULL) | 774 | if (*dst == NULL) |
| 769 | *dst = ip6_route_output(sk, fl); | 775 | *dst = ip6_route_output(sk, fl); |
| 770 | 776 | ||
| @@ -773,7 +779,6 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | |||
| 773 | 779 | ||
| 774 | if (ipv6_addr_any(&fl->fl6_src)) { | 780 | if (ipv6_addr_any(&fl->fl6_src)) { |
| 775 | err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src); | 781 | err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src); |
| 776 | |||
| 777 | if (err) | 782 | if (err) |
| 778 | goto out_err_release; | 783 | goto out_err_release; |
| 779 | } | 784 | } |
| @@ -786,8 +791,48 @@ out_err_release: | |||
| 786 | return err; | 791 | return err; |
| 787 | } | 792 | } |
| 788 | 793 | ||
| 794 | /** | ||
| 795 | * ip6_dst_lookup - perform route lookup on flow | ||
| 796 | * @sk: socket which provides route info | ||
| 797 | * @dst: pointer to dst_entry * for result | ||
| 798 | * @fl: flow to lookup | ||
| 799 | * | ||
| 800 | * This function performs a route lookup on the given flow. | ||
| 801 | * | ||
| 802 | * It returns zero on success, or a standard errno code on error. | ||
| 803 | */ | ||
| 804 | int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | ||
| 805 | { | ||
| 806 | *dst = NULL; | ||
| 807 | return ip6_dst_lookup_tail(sk, dst, fl); | ||
| 808 | } | ||
| 789 | EXPORT_SYMBOL_GPL(ip6_dst_lookup); | 809 | EXPORT_SYMBOL_GPL(ip6_dst_lookup); |
| 790 | 810 | ||
| 811 | /** | ||
| 812 | * ip6_sk_dst_lookup - perform socket cached route lookup on flow | ||
| 813 | * @sk: socket which provides the dst cache and route info | ||
| 814 | * @dst: pointer to dst_entry * for result | ||
| 815 | * @fl: flow to lookup | ||
| 816 | * | ||
| 817 | * This function performs a route lookup on the given flow with the | ||
| 818 | * possibility of using the cached route in the socket if it is valid. | ||
| 819 | * It will take the socket dst lock when operating on the dst cache. | ||
| 820 | * As a result, this function can only be used in process context. | ||
| 821 | * | ||
| 822 | * It returns zero on success, or a standard errno code on error. | ||
| 823 | */ | ||
| 824 | int ip6_sk_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | ||
| 825 | { | ||
| 826 | *dst = NULL; | ||
| 827 | if (sk) { | ||
| 828 | *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); | ||
| 829 | *dst = ip6_sk_dst_check(sk, *dst, fl); | ||
| 830 | } | ||
| 831 | |||
| 832 | return ip6_dst_lookup_tail(sk, dst, fl); | ||
| 833 | } | ||
| 834 | EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup); | ||
| 835 | |||
| 791 | static inline int ip6_ufo_append_data(struct sock *sk, | 836 | static inline int ip6_ufo_append_data(struct sock *sk, |
| 792 | int getfrag(void *from, char *to, int offset, int len, | 837 | int getfrag(void *from, char *to, int offset, int len, |
| 793 | int odd, struct sk_buff *skb), | 838 | int odd, struct sk_buff *skb), |
