|
@@ -198,6 +198,7 @@ static void ip_expire(unsigned long arg)
|
|
qp = container_of((struct inet_frag_queue *) arg, struct ipq, q);
|
|
qp = container_of((struct inet_frag_queue *) arg, struct ipq, q);
|
|
net = container_of(qp->q.net, struct net, ipv4.frags);
|
|
net = container_of(qp->q.net, struct net, ipv4.frags);
|
|
|
|
|
|
|
|
+ rcu_read_lock();
|
|
spin_lock(&qp->q.lock);
|
|
spin_lock(&qp->q.lock);
|
|
|
|
|
|
if (qp->q.flags & INET_FRAG_COMPLETE)
|
|
if (qp->q.flags & INET_FRAG_COMPLETE)
|
|
@@ -207,7 +208,7 @@ static void ip_expire(unsigned long arg)
|
|
__IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS);
|
|
__IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS);
|
|
|
|
|
|
if (!inet_frag_evicting(&qp->q)) {
|
|
if (!inet_frag_evicting(&qp->q)) {
|
|
- struct sk_buff *head = qp->q.fragments;
|
|
|
|
|
|
+ struct sk_buff *clone, *head = qp->q.fragments;
|
|
const struct iphdr *iph;
|
|
const struct iphdr *iph;
|
|
int err;
|
|
int err;
|
|
|
|
|
|
@@ -216,32 +217,40 @@ static void ip_expire(unsigned long arg)
|
|
if (!(qp->q.flags & INET_FRAG_FIRST_IN) || !qp->q.fragments)
|
|
if (!(qp->q.flags & INET_FRAG_FIRST_IN) || !qp->q.fragments)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
- rcu_read_lock();
|
|
|
|
head->dev = dev_get_by_index_rcu(net, qp->iif);
|
|
head->dev = dev_get_by_index_rcu(net, qp->iif);
|
|
if (!head->dev)
|
|
if (!head->dev)
|
|
- goto out_rcu_unlock;
|
|
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
|
|
/* skb has no dst, perform route lookup again */
|
|
/* skb has no dst, perform route lookup again */
|
|
iph = ip_hdr(head);
|
|
iph = ip_hdr(head);
|
|
err = ip_route_input_noref(head, iph->daddr, iph->saddr,
|
|
err = ip_route_input_noref(head, iph->daddr, iph->saddr,
|
|
iph->tos, head->dev);
|
|
iph->tos, head->dev);
|
|
if (err)
|
|
if (err)
|
|
- goto out_rcu_unlock;
|
|
|
|
|
|
+ goto out;
|
|
|
|
|
|
/* Only an end host needs to send an ICMP
|
|
/* Only an end host needs to send an ICMP
|
|
* "Fragment Reassembly Timeout" message, per RFC792.
|
|
* "Fragment Reassembly Timeout" message, per RFC792.
|
|
*/
|
|
*/
|
|
if (frag_expire_skip_icmp(qp->user) &&
|
|
if (frag_expire_skip_icmp(qp->user) &&
|
|
(skb_rtable(head)->rt_type != RTN_LOCAL))
|
|
(skb_rtable(head)->rt_type != RTN_LOCAL))
|
|
- goto out_rcu_unlock;
|
|
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ clone = skb_clone(head, GFP_ATOMIC);
|
|
|
|
|
|
/* Send an ICMP "Fragment Reassembly Timeout" message. */
|
|
/* Send an ICMP "Fragment Reassembly Timeout" message. */
|
|
- icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
|
|
|
|
-out_rcu_unlock:
|
|
|
|
- rcu_read_unlock();
|
|
|
|
|
|
+ if (clone) {
|
|
|
|
+ spin_unlock(&qp->q.lock);
|
|
|
|
+ icmp_send(clone, ICMP_TIME_EXCEEDED,
|
|
|
|
+ ICMP_EXC_FRAGTIME, 0);
|
|
|
|
+ consume_skb(clone);
|
|
|
|
+ goto out_rcu_unlock;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
out:
|
|
out:
|
|
spin_unlock(&qp->q.lock);
|
|
spin_unlock(&qp->q.lock);
|
|
|
|
+out_rcu_unlock:
|
|
|
|
+ rcu_read_unlock();
|
|
ipq_put(qp);
|
|
ipq_put(qp);
|
|
}
|
|
}
|
|
|
|
|