aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c129
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
726int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) 729static 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
765out:
766 return dst;
767}
768
769static 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 */
804int 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}
789EXPORT_SYMBOL_GPL(ip6_dst_lookup); 809EXPORT_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 */
824int 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}
834EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup);
835
791static inline int ip6_ufo_append_data(struct sock *sk, 836static 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),