]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/ipv6/ip6_output.c
ipv6: Don't increase IPSTATS_MIB_FRAGFAILS twice in ip6_fragment()
[karo-tx-linux.git] / net / ipv6 / ip6_output.c
index bf8a58a1c32d83a9605844075da5815be23a6bf1..162efba0d0cd851848363588318cf6ade4a5a62c 100644 (file)
@@ -67,9 +67,6 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
        struct in6_addr *nexthop;
        int ret;
 
-       skb->protocol = htons(ETH_P_IPV6);
-       skb->dev = dev;
-
        if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
                struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
 
@@ -154,6 +151,9 @@ 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));
 
+       skb->protocol = htons(ETH_P_IPV6);
+       skb->dev = dev;
+
        if (unlikely(idev->cnf.disable_ipv6)) {
                IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
                kfree_skb(skb);
@@ -673,8 +673,6 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
                *prevhdr = NEXTHDR_FRAGMENT;
                tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC);
                if (!tmp_hdr) {
-                       IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
-                                     IPSTATS_MIB_FRAGFAILS);
                        err = -ENOMEM;
                        goto fail;
                }
@@ -682,7 +680,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
                skb_frag_list_init(skb);
 
                __skb_pull(skb, hlen);
-               fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr));
+               fh = __skb_push(skb, sizeof(struct frag_hdr));
                __skb_push(skb, hlen);
                skb_reset_network_header(skb);
                memcpy(skb_network_header(skb), tmp_hdr, hlen);
@@ -698,15 +696,13 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
                ipv6_hdr(skb)->payload_len = htons(first_len -
                                                   sizeof(struct ipv6hdr));
 
-               dst_hold(&rt->dst);
-
                for (;;) {
                        /* Prepare header of the next frame,
                         * before previous one went down. */
                        if (frag) {
                                frag->ip_summed = CHECKSUM_NONE;
                                skb_reset_transport_header(frag);
-                               fh = (struct frag_hdr *)__skb_push(frag, sizeof(struct frag_hdr));
+                               fh = __skb_push(frag, sizeof(struct frag_hdr));
                                __skb_push(frag, hlen);
                                skb_reset_network_header(frag);
                                memcpy(skb_network_header(frag), tmp_hdr,
@@ -742,7 +738,6 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
                if (err == 0) {
                        IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
                                      IPSTATS_MIB_FRAGOKS);
-                       ip6_rt_put(rt);
                        return 0;
                }
 
@@ -750,7 +745,6 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
 
                IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
                              IPSTATS_MIB_FRAGFAILS);
-               ip6_rt_put(rt);
                return err;
 
 slow_path_clean:
@@ -793,8 +787,6 @@ slow_path:
                frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) +
                                 hroom + troom, GFP_ATOMIC);
                if (!frag) {
-                       IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
-                                     IPSTATS_MIB_FRAGFAILS);
                        err = -ENOMEM;
                        goto fail;
                }
@@ -869,7 +861,6 @@ fail_toobig:
        if (skb->sk && dst_allfrag(skb_dst(skb)))
                sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK);
 
-       skb->dev = skb_dst(skb)->dev;
        icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
        err = -EMSGSIZE;
 
@@ -1390,7 +1381,7 @@ emsgsize:
         */
 
        cork->length += length;
-       if ((((length + fragheaderlen) > mtu) ||
+       if ((((length + (skb ? skb->len : headersize)) > mtu) ||
             (skb && skb_is_gso(skb))) &&
            (sk->sk_protocol == IPPROTO_UDP) &&
            (rt->dst.dev->features & NETIF_F_UFO) && !dst_xfrm(&rt->dst) &&
@@ -1477,7 +1468,7 @@ alloc_new_skb:
                                                (flags & MSG_DONTWAIT), &err);
                        } else {
                                skb = NULL;
-                               if (atomic_read(&sk->sk_wmem_alloc) <=
+                               if (refcount_read(&sk->sk_wmem_alloc) <=
                                    2 * sk->sk_sndbuf)
                                        skb = sock_wmalloc(sk,
                                                           alloclen + hh_len, 1,
@@ -1586,7 +1577,7 @@ alloc_new_skb:
                        skb->len += copy;
                        skb->data_len += copy;
                        skb->truesize += copy;
-                       atomic_add(copy, &sk->sk_wmem_alloc);
+                       refcount_add(copy, &sk->sk_wmem_alloc);
                }
                offset += copy;
                length -= copy;