aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_fragment.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/ip_fragment.c')
-rw-r--r--net/ipv4/ip_fragment.c67
1 files changed, 41 insertions, 26 deletions
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index cd6ce6ac6358..2152d222b954 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -5,8 +5,6 @@
5 * 5 *
6 * The IP fragmentation functionality. 6 * The IP fragmentation functionality.
7 * 7 *
8 * Version: $Id: ip_fragment.c,v 1.59 2002/01/12 07:54:56 davem Exp $
9 *
10 * Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG> 8 * Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
11 * Alan Cox <Alan.Cox@linux.org> 9 * Alan Cox <Alan.Cox@linux.org>
12 * 10 *
@@ -180,7 +178,7 @@ static void ip_evictor(struct net *net)
180 178
181 evicted = inet_frag_evictor(&net->ipv4.frags, &ip4_frags); 179 evicted = inet_frag_evictor(&net->ipv4.frags, &ip4_frags);
182 if (evicted) 180 if (evicted)
183 IP_ADD_STATS_BH(IPSTATS_MIB_REASMFAILS, evicted); 181 IP_ADD_STATS_BH(net, IPSTATS_MIB_REASMFAILS, evicted);
184} 182}
185 183
186/* 184/*
@@ -189,8 +187,10 @@ static void ip_evictor(struct net *net)
189static void ip_expire(unsigned long arg) 187static void ip_expire(unsigned long arg)
190{ 188{
191 struct ipq *qp; 189 struct ipq *qp;
190 struct net *net;
192 191
193 qp = container_of((struct inet_frag_queue *) arg, struct ipq, q); 192 qp = container_of((struct inet_frag_queue *) arg, struct ipq, q);
193 net = container_of(qp->q.net, struct net, ipv4.frags);
194 194
195 spin_lock(&qp->q.lock); 195 spin_lock(&qp->q.lock);
196 196
@@ -199,14 +199,12 @@ static void ip_expire(unsigned long arg)
199 199
200 ipq_kill(qp); 200 ipq_kill(qp);
201 201
202 IP_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT); 202 IP_INC_STATS_BH(net, IPSTATS_MIB_REASMTIMEOUT);
203 IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); 203 IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS);
204 204
205 if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { 205 if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) {
206 struct sk_buff *head = qp->q.fragments; 206 struct sk_buff *head = qp->q.fragments;
207 struct net *net;
208 207
209 net = container_of(qp->q.net, struct net, ipv4.frags);
210 /* Send an ICMP "Fragment Reassembly Timeout" message. */ 208 /* Send an ICMP "Fragment Reassembly Timeout" message. */
211 if ((head->dev = dev_get_by_index(net, qp->iif)) != NULL) { 209 if ((head->dev = dev_get_by_index(net, qp->iif)) != NULL) {
212 icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); 210 icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
@@ -229,6 +227,8 @@ static inline struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user)
229 227
230 arg.iph = iph; 228 arg.iph = iph;
231 arg.user = user; 229 arg.user = user;
230
231 read_lock(&ip4_frags.lock);
232 hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol); 232 hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);
233 233
234 q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash); 234 q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash);
@@ -261,7 +261,10 @@ static inline int ip_frag_too_far(struct ipq *qp)
261 rc = qp->q.fragments && (end - start) > max; 261 rc = qp->q.fragments && (end - start) > max;
262 262
263 if (rc) { 263 if (rc) {
264 IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); 264 struct net *net;
265
266 net = container_of(qp->q.net, struct net, ipv4.frags);
267 IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS);
265 } 268 }
266 269
267 return rc; 270 return rc;
@@ -485,8 +488,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
485 qp->q.fragments = head; 488 qp->q.fragments = head;
486 } 489 }
487 490
488 BUG_TRAP(head != NULL); 491 WARN_ON(head == NULL);
489 BUG_TRAP(FRAG_CB(head)->offset == 0); 492 WARN_ON(FRAG_CB(head)->offset != 0);
490 493
491 /* Allocate a new buffer for the datagram. */ 494 /* Allocate a new buffer for the datagram. */
492 ihlen = ip_hdrlen(head); 495 ihlen = ip_hdrlen(head);
@@ -545,7 +548,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
545 iph = ip_hdr(head); 548 iph = ip_hdr(head);
546 iph->frag_off = 0; 549 iph->frag_off = 0;
547 iph->tot_len = htons(len); 550 iph->tot_len = htons(len);
548 IP_INC_STATS_BH(IPSTATS_MIB_REASMOKS); 551 IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_REASMOKS);
549 qp->q.fragments = NULL; 552 qp->q.fragments = NULL;
550 return 0; 553 return 0;
551 554
@@ -560,7 +563,7 @@ out_oversize:
560 "Oversized IP packet from " NIPQUAD_FMT ".\n", 563 "Oversized IP packet from " NIPQUAD_FMT ".\n",
561 NIPQUAD(qp->saddr)); 564 NIPQUAD(qp->saddr));
562out_fail: 565out_fail:
563 IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); 566 IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_REASMFAILS);
564 return err; 567 return err;
565} 568}
566 569
@@ -570,9 +573,9 @@ int ip_defrag(struct sk_buff *skb, u32 user)
570 struct ipq *qp; 573 struct ipq *qp;
571 struct net *net; 574 struct net *net;
572 575
573 IP_INC_STATS_BH(IPSTATS_MIB_REASMREQDS);
574
575 net = skb->dev ? dev_net(skb->dev) : dev_net(skb->dst->dev); 576 net = skb->dev ? dev_net(skb->dev) : dev_net(skb->dst->dev);
577 IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS);
578
576 /* Start by cleaning up the memory. */ 579 /* Start by cleaning up the memory. */
577 if (atomic_read(&net->ipv4.frags.mem) > net->ipv4.frags.high_thresh) 580 if (atomic_read(&net->ipv4.frags.mem) > net->ipv4.frags.high_thresh)
578 ip_evictor(net); 581 ip_evictor(net);
@@ -590,7 +593,7 @@ int ip_defrag(struct sk_buff *skb, u32 user)
590 return ret; 593 return ret;
591 } 594 }
592 595
593 IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); 596 IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS);
594 kfree_skb(skb); 597 kfree_skb(skb);
595 return -ENOMEM; 598 return -ENOMEM;
596} 599}
@@ -598,7 +601,7 @@ int ip_defrag(struct sk_buff *skb, u32 user)
598#ifdef CONFIG_SYSCTL 601#ifdef CONFIG_SYSCTL
599static int zero; 602static int zero;
600 603
601static struct ctl_table ip4_frags_ctl_table[] = { 604static struct ctl_table ip4_frags_ns_ctl_table[] = {
602 { 605 {
603 .ctl_name = NET_IPV4_IPFRAG_HIGH_THRESH, 606 .ctl_name = NET_IPV4_IPFRAG_HIGH_THRESH,
604 .procname = "ipfrag_high_thresh", 607 .procname = "ipfrag_high_thresh",
@@ -624,6 +627,10 @@ static struct ctl_table ip4_frags_ctl_table[] = {
624 .proc_handler = &proc_dointvec_jiffies, 627 .proc_handler = &proc_dointvec_jiffies,
625 .strategy = &sysctl_jiffies 628 .strategy = &sysctl_jiffies
626 }, 629 },
630 { }
631};
632
633static struct ctl_table ip4_frags_ctl_table[] = {
627 { 634 {
628 .ctl_name = NET_IPV4_IPFRAG_SECRET_INTERVAL, 635 .ctl_name = NET_IPV4_IPFRAG_SECRET_INTERVAL,
629 .procname = "ipfrag_secret_interval", 636 .procname = "ipfrag_secret_interval",
@@ -644,22 +651,20 @@ static struct ctl_table ip4_frags_ctl_table[] = {
644 { } 651 { }
645}; 652};
646 653
647static int ip4_frags_ctl_register(struct net *net) 654static int ip4_frags_ns_ctl_register(struct net *net)
648{ 655{
649 struct ctl_table *table; 656 struct ctl_table *table;
650 struct ctl_table_header *hdr; 657 struct ctl_table_header *hdr;
651 658
652 table = ip4_frags_ctl_table; 659 table = ip4_frags_ns_ctl_table;
653 if (net != &init_net) { 660 if (net != &init_net) {
654 table = kmemdup(table, sizeof(ip4_frags_ctl_table), GFP_KERNEL); 661 table = kmemdup(table, sizeof(ip4_frags_ns_ctl_table), GFP_KERNEL);
655 if (table == NULL) 662 if (table == NULL)
656 goto err_alloc; 663 goto err_alloc;
657 664
658 table[0].data = &net->ipv4.frags.high_thresh; 665 table[0].data = &net->ipv4.frags.high_thresh;
659 table[1].data = &net->ipv4.frags.low_thresh; 666 table[1].data = &net->ipv4.frags.low_thresh;
660 table[2].data = &net->ipv4.frags.timeout; 667 table[2].data = &net->ipv4.frags.timeout;
661 table[3].mode &= ~0222;
662 table[4].mode &= ~0222;
663 } 668 }
664 669
665 hdr = register_net_sysctl_table(net, net_ipv4_ctl_path, table); 670 hdr = register_net_sysctl_table(net, net_ipv4_ctl_path, table);
@@ -676,7 +681,7 @@ err_alloc:
676 return -ENOMEM; 681 return -ENOMEM;
677} 682}
678 683
679static void ip4_frags_ctl_unregister(struct net *net) 684static void ip4_frags_ns_ctl_unregister(struct net *net)
680{ 685{
681 struct ctl_table *table; 686 struct ctl_table *table;
682 687
@@ -684,13 +689,22 @@ static void ip4_frags_ctl_unregister(struct net *net)
684 unregister_net_sysctl_table(net->ipv4.frags_hdr); 689 unregister_net_sysctl_table(net->ipv4.frags_hdr);
685 kfree(table); 690 kfree(table);
686} 691}
692
693static void ip4_frags_ctl_register(void)
694{
695 register_net_sysctl_rotable(net_ipv4_ctl_path, ip4_frags_ctl_table);
696}
687#else 697#else
688static inline int ip4_frags_ctl_register(struct net *net) 698static inline int ip4_frags_ns_ctl_register(struct net *net)
689{ 699{
690 return 0; 700 return 0;
691} 701}
692 702
693static inline void ip4_frags_ctl_unregister(struct net *net) 703static inline void ip4_frags_ns_ctl_unregister(struct net *net)
704{
705}
706
707static inline void ip4_frags_ctl_register(void)
694{ 708{
695} 709}
696#endif 710#endif
@@ -714,12 +728,12 @@ static int ipv4_frags_init_net(struct net *net)
714 728
715 inet_frags_init_net(&net->ipv4.frags); 729 inet_frags_init_net(&net->ipv4.frags);
716 730
717 return ip4_frags_ctl_register(net); 731 return ip4_frags_ns_ctl_register(net);
718} 732}
719 733
720static void ipv4_frags_exit_net(struct net *net) 734static void ipv4_frags_exit_net(struct net *net)
721{ 735{
722 ip4_frags_ctl_unregister(net); 736 ip4_frags_ns_ctl_unregister(net);
723 inet_frags_exit_net(&net->ipv4.frags, &ip4_frags); 737 inet_frags_exit_net(&net->ipv4.frags, &ip4_frags);
724} 738}
725 739
@@ -730,6 +744,7 @@ static struct pernet_operations ip4_frags_ops = {
730 744
731void __init ipfrag_init(void) 745void __init ipfrag_init(void)
732{ 746{
747 ip4_frags_ctl_register();
733 register_pernet_subsys(&ip4_frags_ops); 748 register_pernet_subsys(&ip4_frags_ops);
734 ip4_frags.hashfn = ip4_hashfn; 749 ip4_frags.hashfn = ip4_hashfn;
735 ip4_frags.constructor = ip4_frag_init; 750 ip4_frags.constructor = ip4_frag_init;