Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[firefly-linux-kernel-4.4.55.git] / net / ipv6 / ip6_output.c
index caf7d14a1bdda66df36ed5d610519ddcdd9c67fb..3c8e9d8795cdbfff8f46408614e05853fae5cafb 100644 (file)
@@ -55,6 +55,7 @@
 #include <net/xfrm.h>
 #include <net/checksum.h>
 #include <linux/mroute6.h>
+#include <net/l3mdev.h>
 
 static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
@@ -130,11 +131,10 @@ static int ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff *s
                return ip6_finish_output2(net, sk, skb);
 }
 
-int ip6_output(struct sock *sk, struct sk_buff *skb)
+int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
        struct net_device *dev = skb_dst(skb)->dev;
        struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
-       struct net *net = dev_net(dev);
 
        if (unlikely(idev->cnf.disable_ipv6)) {
                IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
@@ -233,7 +233,7 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
                 */
                return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
                               net, (struct sock *)sk, skb, NULL, dst->dev,
-                              dst_output_okfn);
+                              dst_output);
        }
 
        skb->dev = dst->dev;
@@ -333,7 +333,7 @@ static inline int ip6_forward_finish(struct net *net, struct sock *sk,
                                     struct sk_buff *skb)
 {
        skb_sender_cpu_clear(skb);
-       return dst_output(sk, skb);
+       return dst_output(net, sk, skb);
 }
 
 static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
@@ -389,6 +389,9 @@ int ip6_forward(struct sk_buff *skb)
        if (skb->pkt_type != PACKET_HOST)
                goto drop;
 
+       if (unlikely(skb->sk))
+               goto drop;
+
        if (skb_warn_if_lro(skb))
                goto drop;
 
@@ -593,6 +596,8 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
                if (np->frag_size)
                        mtu = np->frag_size;
        }
+       if (mtu < hlen + sizeof(struct frag_hdr) + 8)
+               goto fail_toobig;
        mtu -= hlen + sizeof(struct frag_hdr);
 
        frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr,
@@ -886,7 +891,8 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
 #ifdef CONFIG_IPV6_SUBTREES
            ip6_rt_check(&rt->rt6i_src, &fl6->saddr, np->saddr_cache) ||
 #endif
-           (fl6->flowi6_oif && fl6->flowi6_oif != dst->dev->ifindex)) {
+          (!(fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF) &&
+             (fl6->flowi6_oif && fl6->flowi6_oif != dst->dev->ifindex))) {
                dst_release(dst);
                dst = NULL;
        }
@@ -1038,7 +1044,7 @@ struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 *fl6,
        if (final_dst)
                fl6->daddr = *final_dst;
        if (!fl6->flowi6_oif)
-               fl6->flowi6_oif = dst->dev->ifindex;
+               fl6->flowi6_oif = l3mdev_fib_oif(dst->dev);
 
        return xfrm_lookup_route(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0);
 }
@@ -1692,7 +1698,7 @@ int ip6_send_skb(struct sk_buff *skb)
        struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
        int err;
 
-       err = ip6_local_out(skb);
+       err = ip6_local_out(net, skb->sk, skb);
        if (err) {
                if (err > 0)
                        err = net_xmit_errno(err);