FN(IP_INADDRERRORS)             \
        FN(IP_INNOROUTES)               \
        FN(PKT_TOO_BIG)                 \
+       FN(DUP_FRAG)                    \
        FNe(MAX)
 
 /**
         * MTU)
         */
        SKB_DROP_REASON_PKT_TOO_BIG,
+       /** @SKB_DROP_REASON_DUP_FRAG: duplicate fragment */
+       SKB_DROP_REASON_DUP_FRAG,
        /**
         * @SKB_DROP_REASON_MAX: the maximum of drop reason, which shouldn't be
         * used as a real 'reason'
 
        struct net_device *dev;
        unsigned int fragsize;
        int err = -ENOENT;
+       SKB_DR(reason);
        u8 ecn;
 
-       if (qp->q.flags & INET_FRAG_COMPLETE)
+       /* If reassembly is already done, @skb must be a duplicate frag. */
+       if (qp->q.flags & INET_FRAG_COMPLETE) {
+               SKB_DR_SET(reason, DUP_FRAG);
                goto err;
+       }
 
        if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) &&
            unlikely(ip_frag_too_far(qp)) &&
 
 insert_error:
        if (err == IPFRAG_DUP) {
-               kfree_skb(skb);
-               return -EINVAL;
+               SKB_DR_SET(reason, DUP_FRAG);
+               err = -EINVAL;
+               goto err;
        }
        err = -EINVAL;
        __IP_INC_STATS(net, IPSTATS_MIB_REASM_OVERLAPS);
        inet_frag_kill(&qp->q);
        __IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS);
 err:
-       kfree_skb(skb);
+       kfree_skb_reason(skb, reason);
        return err;
 }
 
 
        if (err) {
                if (err == IPFRAG_DUP) {
                        /* No error for duplicates, pretend they got queued. */
-                       kfree_skb(skb);
+                       kfree_skb_reason(skb, SKB_DROP_REASON_DUP_FRAG);
                        return -EINPROGRESS;
                }
                goto insert_error;
 
        struct sk_buff *prev_tail;
        struct net_device *dev;
        int err = -ENOENT;
+       SKB_DR(reason);
        u8 ecn;
 
-       if (fq->q.flags & INET_FRAG_COMPLETE)
+       /* If reassembly is already done, @skb must be a duplicate frag. */
+       if (fq->q.flags & INET_FRAG_COMPLETE) {
+               SKB_DR_SET(reason, DUP_FRAG);
                goto err;
+       }
 
        err = -EINVAL;
        offset = ntohs(fhdr->frag_off) & ~0x7;
 
 insert_error:
        if (err == IPFRAG_DUP) {
-               kfree_skb(skb);
-               return -EINVAL;
+               SKB_DR_SET(reason, DUP_FRAG);
+               err = -EINVAL;
+               goto err;
        }
        err = -EINVAL;
        __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
        __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
                        IPSTATS_MIB_REASMFAILS);
 err:
-       kfree_skb(skb);
+       kfree_skb_reason(skb, reason);
        return err;
 }