diff options
Diffstat (limited to 'net/ipv4/ip_fragment.c')
-rw-r--r-- | net/ipv4/ip_fragment.c | 53 |
1 files changed, 37 insertions, 16 deletions
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index d3fe10be7219..75347ea70ea0 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c | |||
@@ -32,6 +32,9 @@ | |||
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 <linux/slab.h> | ||
36 | #include <net/route.h> | ||
37 | #include <net/dst.h> | ||
35 | #include <net/sock.h> | 38 | #include <net/sock.h> |
36 | #include <net/ip.h> | 39 | #include <net/ip.h> |
37 | #include <net/icmp.h> | 40 | #include <net/icmp.h> |
@@ -205,11 +208,35 @@ static void ip_expire(unsigned long arg) | |||
205 | if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { | 208 | if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { |
206 | struct sk_buff *head = qp->q.fragments; | 209 | struct sk_buff *head = qp->q.fragments; |
207 | 210 | ||
208 | /* Send an ICMP "Fragment Reassembly Timeout" message. */ | 211 | rcu_read_lock(); |
209 | if ((head->dev = dev_get_by_index(net, qp->iif)) != NULL) { | 212 | head->dev = dev_get_by_index_rcu(net, qp->iif); |
210 | icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); | 213 | if (!head->dev) |
211 | dev_put(head->dev); | 214 | goto out_rcu_unlock; |
215 | |||
216 | /* | ||
217 | * Only search router table for the head fragment, | ||
218 | * when defraging timeout at PRE_ROUTING HOOK. | ||
219 | */ | ||
220 | if (qp->user == IP_DEFRAG_CONNTRACK_IN && !skb_dst(head)) { | ||
221 | const struct iphdr *iph = ip_hdr(head); | ||
222 | int err = ip_route_input(head, iph->daddr, iph->saddr, | ||
223 | iph->tos, head->dev); | ||
224 | if (unlikely(err)) | ||
225 | goto out_rcu_unlock; | ||
226 | |||
227 | /* | ||
228 | * Only an end host needs to send an ICMP | ||
229 | * "Fragment Reassembly Timeout" message, per RFC792. | ||
230 | */ | ||
231 | if (skb_rtable(head)->rt_type != RTN_LOCAL) | ||
232 | goto out_rcu_unlock; | ||
233 | |||
212 | } | 234 | } |
235 | |||
236 | /* Send an ICMP "Fragment Reassembly Timeout" message. */ | ||
237 | icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); | ||
238 | out_rcu_unlock: | ||
239 | rcu_read_unlock(); | ||
213 | } | 240 | } |
214 | out: | 241 | out: |
215 | spin_unlock(&qp->q.lock); | 242 | spin_unlock(&qp->q.lock); |
@@ -603,7 +630,6 @@ static int zero; | |||
603 | 630 | ||
604 | static struct ctl_table ip4_frags_ns_ctl_table[] = { | 631 | static struct ctl_table ip4_frags_ns_ctl_table[] = { |
605 | { | 632 | { |
606 | .ctl_name = NET_IPV4_IPFRAG_HIGH_THRESH, | ||
607 | .procname = "ipfrag_high_thresh", | 633 | .procname = "ipfrag_high_thresh", |
608 | .data = &init_net.ipv4.frags.high_thresh, | 634 | .data = &init_net.ipv4.frags.high_thresh, |
609 | .maxlen = sizeof(int), | 635 | .maxlen = sizeof(int), |
@@ -611,7 +637,6 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = { | |||
611 | .proc_handler = proc_dointvec | 637 | .proc_handler = proc_dointvec |
612 | }, | 638 | }, |
613 | { | 639 | { |
614 | .ctl_name = NET_IPV4_IPFRAG_LOW_THRESH, | ||
615 | .procname = "ipfrag_low_thresh", | 640 | .procname = "ipfrag_low_thresh", |
616 | .data = &init_net.ipv4.frags.low_thresh, | 641 | .data = &init_net.ipv4.frags.low_thresh, |
617 | .maxlen = sizeof(int), | 642 | .maxlen = sizeof(int), |
@@ -619,26 +644,22 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = { | |||
619 | .proc_handler = proc_dointvec | 644 | .proc_handler = proc_dointvec |
620 | }, | 645 | }, |
621 | { | 646 | { |
622 | .ctl_name = NET_IPV4_IPFRAG_TIME, | ||
623 | .procname = "ipfrag_time", | 647 | .procname = "ipfrag_time", |
624 | .data = &init_net.ipv4.frags.timeout, | 648 | .data = &init_net.ipv4.frags.timeout, |
625 | .maxlen = sizeof(int), | 649 | .maxlen = sizeof(int), |
626 | .mode = 0644, | 650 | .mode = 0644, |
627 | .proc_handler = proc_dointvec_jiffies, | 651 | .proc_handler = proc_dointvec_jiffies, |
628 | .strategy = sysctl_jiffies | ||
629 | }, | 652 | }, |
630 | { } | 653 | { } |
631 | }; | 654 | }; |
632 | 655 | ||
633 | static struct ctl_table ip4_frags_ctl_table[] = { | 656 | static struct ctl_table ip4_frags_ctl_table[] = { |
634 | { | 657 | { |
635 | .ctl_name = NET_IPV4_IPFRAG_SECRET_INTERVAL, | ||
636 | .procname = "ipfrag_secret_interval", | 658 | .procname = "ipfrag_secret_interval", |
637 | .data = &ip4_frags.secret_interval, | 659 | .data = &ip4_frags.secret_interval, |
638 | .maxlen = sizeof(int), | 660 | .maxlen = sizeof(int), |
639 | .mode = 0644, | 661 | .mode = 0644, |
640 | .proc_handler = proc_dointvec_jiffies, | 662 | .proc_handler = proc_dointvec_jiffies, |
641 | .strategy = sysctl_jiffies | ||
642 | }, | 663 | }, |
643 | { | 664 | { |
644 | .procname = "ipfrag_max_dist", | 665 | .procname = "ipfrag_max_dist", |
@@ -651,13 +672,13 @@ static struct ctl_table ip4_frags_ctl_table[] = { | |||
651 | { } | 672 | { } |
652 | }; | 673 | }; |
653 | 674 | ||
654 | static int ip4_frags_ns_ctl_register(struct net *net) | 675 | static int __net_init ip4_frags_ns_ctl_register(struct net *net) |
655 | { | 676 | { |
656 | struct ctl_table *table; | 677 | struct ctl_table *table; |
657 | struct ctl_table_header *hdr; | 678 | struct ctl_table_header *hdr; |
658 | 679 | ||
659 | table = ip4_frags_ns_ctl_table; | 680 | table = ip4_frags_ns_ctl_table; |
660 | if (net != &init_net) { | 681 | if (!net_eq(net, &init_net)) { |
661 | table = kmemdup(table, sizeof(ip4_frags_ns_ctl_table), GFP_KERNEL); | 682 | table = kmemdup(table, sizeof(ip4_frags_ns_ctl_table), GFP_KERNEL); |
662 | if (table == NULL) | 683 | if (table == NULL) |
663 | goto err_alloc; | 684 | goto err_alloc; |
@@ -675,13 +696,13 @@ static int ip4_frags_ns_ctl_register(struct net *net) | |||
675 | return 0; | 696 | return 0; |
676 | 697 | ||
677 | err_reg: | 698 | err_reg: |
678 | if (net != &init_net) | 699 | if (!net_eq(net, &init_net)) |
679 | kfree(table); | 700 | kfree(table); |
680 | err_alloc: | 701 | err_alloc: |
681 | return -ENOMEM; | 702 | return -ENOMEM; |
682 | } | 703 | } |
683 | 704 | ||
684 | static void ip4_frags_ns_ctl_unregister(struct net *net) | 705 | static void __net_exit ip4_frags_ns_ctl_unregister(struct net *net) |
685 | { | 706 | { |
686 | struct ctl_table *table; | 707 | struct ctl_table *table; |
687 | 708 | ||
@@ -709,7 +730,7 @@ static inline void ip4_frags_ctl_register(void) | |||
709 | } | 730 | } |
710 | #endif | 731 | #endif |
711 | 732 | ||
712 | static int ipv4_frags_init_net(struct net *net) | 733 | static int __net_init ipv4_frags_init_net(struct net *net) |
713 | { | 734 | { |
714 | /* | 735 | /* |
715 | * Fragment cache limits. We will commit 256K at one time. Should we | 736 | * Fragment cache limits. We will commit 256K at one time. Should we |
@@ -731,7 +752,7 @@ static int ipv4_frags_init_net(struct net *net) | |||
731 | return ip4_frags_ns_ctl_register(net); | 752 | return ip4_frags_ns_ctl_register(net); |
732 | } | 753 | } |
733 | 754 | ||
734 | static void ipv4_frags_exit_net(struct net *net) | 755 | static void __net_exit ipv4_frags_exit_net(struct net *net) |
735 | { | 756 | { |
736 | ip4_frags_ns_ctl_unregister(net); | 757 | ip4_frags_ns_ctl_unregister(net); |
737 | inet_frags_exit_net(&net->ipv4.frags, &ip4_frags); | 758 | inet_frags_exit_net(&net->ipv4.frags, &ip4_frags); |