diff options
-rw-r--r-- | net/ipv4/ip_fragment.c | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 891c72aea520..9f41bd311754 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include <linux/netdevice.h> | 32 | #include <linux/netdevice.h> |
33 | #include <linux/jhash.h> | 33 | #include <linux/jhash.h> |
34 | #include <linux/random.h> | 34 | #include <linux/random.h> |
35 | #include <net/route.h> | ||
36 | #include <net/dst.h> | ||
35 | #include <net/sock.h> | 37 | #include <net/sock.h> |
36 | #include <net/ip.h> | 38 | #include <net/ip.h> |
37 | #include <net/icmp.h> | 39 | #include <net/icmp.h> |
@@ -205,13 +207,37 @@ static void ip_expire(unsigned long arg) | |||
205 | if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { | 207 | if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { |
206 | struct sk_buff *head = qp->q.fragments; | 208 | struct sk_buff *head = qp->q.fragments; |
207 | 209 | ||
208 | /* Send an ICMP "Fragment Reassembly Timeout" message. */ | ||
209 | rcu_read_lock(); | 210 | rcu_read_lock(); |
210 | head->dev = dev_get_by_index_rcu(net, qp->iif); | 211 | head->dev = dev_get_by_index_rcu(net, qp->iif); |
211 | if (head->dev) | 212 | if (!head->dev) |
212 | icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); | 213 | goto out_rcu_unlock; |
213 | rcu_read_unlock(); | 214 | |
215 | /* | ||
216 | * Only search router table for the head fragment, | ||
217 | * when defraging timeout at PRE_ROUTING HOOK. | ||
218 | */ | ||
219 | if (qp->user == IP_DEFRAG_CONNTRACK_IN && !skb_dst(head)) { | ||
220 | const struct iphdr *iph = ip_hdr(head); | ||
221 | int err = ip_route_input(head, iph->daddr, iph->saddr, | ||
222 | iph->tos, head->dev); | ||
223 | if (unlikely(err)) | ||
224 | goto out_rcu_unlock; | ||
225 | |||
226 | /* | ||
227 | * Only an end host needs to send an ICMP | ||
228 | * "Fragment Reassembly Timeout" message, per RFC792. | ||
229 | */ | ||
230 | if (skb_rtable(head)->rt_type != RTN_LOCAL) | ||
231 | goto out_rcu_unlock; | ||
232 | |||
233 | } | ||
234 | |||
235 | /* Send an ICMP "Fragment Reassembly Timeout" message. */ | ||
236 | icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); | ||
214 | } | 237 | } |
238 | |||
239 | out_rcu_unlock: | ||
240 | rcu_read_unlock(); | ||
215 | out: | 241 | out: |
216 | spin_unlock(&qp->q.lock); | 242 | spin_unlock(&qp->q.lock); |
217 | ipq_put(qp); | 243 | ipq_put(qp); |