net: sctp: inherit auth_capable on INIT collisions
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / ip_fragment.c
index a6445b843ef40774f2bf5014e6800e1f4fd86b3e..b66910aaef4d633977d2e983f2c63b419da38f77 100644 (file)
@@ -79,40 +79,11 @@ struct ipq {
        struct inet_peer *peer;
 };
 
-/* RFC 3168 support :
- * We want to check ECN values of all fragments, do detect invalid combinations.
- * In ipq->ecn, we store the OR value of each ip4_frag_ecn() fragment value.
- */
-#define        IPFRAG_ECN_NOT_ECT      0x01 /* one frag had ECN_NOT_ECT */
-#define        IPFRAG_ECN_ECT_1        0x02 /* one frag had ECN_ECT_1 */
-#define        IPFRAG_ECN_ECT_0        0x04 /* one frag had ECN_ECT_0 */
-#define        IPFRAG_ECN_CE           0x08 /* one frag had ECN_CE */
-
 static inline u8 ip4_frag_ecn(u8 tos)
 {
        return 1 << (tos & INET_ECN_MASK);
 }
 
-/* Given the OR values of all fragments, apply RFC 3168 5.3 requirements
- * Value : 0xff if frame should be dropped.
- *         0 or INET_ECN_CE value, to be ORed in to final iph->tos field
- */
-static const u8 ip4_frag_ecn_table[16] = {
-       /* at least one fragment had CE, and others ECT_0 or ECT_1 */
-       [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0]                      = INET_ECN_CE,
-       [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_1]                      = INET_ECN_CE,
-       [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1]   = INET_ECN_CE,
-
-       /* invalid combinations : drop frame */
-       [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE] = 0xff,
-       [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_0] = 0xff,
-       [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_1] = 0xff,
-       [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = 0xff,
-       [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0] = 0xff,
-       [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_1] = 0xff,
-       [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = 0xff,
-};
-
 static struct inet_frags ip4_frags;
 
 int ip_frag_nqueues(struct net *net)
@@ -248,8 +219,7 @@ static void ip_expire(unsigned long arg)
                if (!head->dev)
                        goto out_rcu_unlock;
 
-               /* skb dst is stale, drop it, and perform route lookup again */
-               skb_dst_drop(head);
+               /* skb has no dst, perform route lookup again */
                iph = ip_hdr(head);
                err = ip_route_input_noref(head, iph->daddr, iph->saddr,
                                           iph->tos, head->dev);
@@ -523,9 +493,16 @@ found:
                qp->q.max_size = skb->len + ihl;
 
        if (qp->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
-           qp->q.meat == qp->q.len)
-               return ip_frag_reasm(qp, prev, dev);
+           qp->q.meat == qp->q.len) {
+               unsigned long orefdst = skb->_skb_refdst;
+
+               skb->_skb_refdst = 0UL;
+               err = ip_frag_reasm(qp, prev, dev);
+               skb->_skb_refdst = orefdst;
+               return err;
+       }
 
+       skb_dst_drop(skb);
        inet_frag_lru_move(&qp->q);
        return -EINPROGRESS;
 
@@ -551,7 +528,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
 
        ipq_kill(qp);
 
-       ecn = ip4_frag_ecn_table[qp->ecn];
+       ecn = ip_frag_ecn_table[qp->ecn];
        if (unlikely(ecn == 0xff)) {
                err = -EINVAL;
                goto out_fail;