aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ip6_tunnel.c26
-rw-r--r--net/ipv6/ip6mr.c22
-rw-r--r--net/ipv6/netfilter/Kconfig12
-rw-r--r--net/ipv6/netfilter/Makefile1
-rw-r--r--net/ipv6/netfilter/ip6_queue.c3
-rw-r--r--net/ipv6/netfilter/ip6table_security.c172
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c5
-rw-r--r--net/ipv6/reassembly.c61
-rw-r--r--net/ipv6/sit.c24
-rw-r--r--net/ipv6/sysctl_net_ipv6.c29
10 files changed, 281 insertions, 74 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 2bda3ba100b1..37814810ac49 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -711,7 +711,7 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
711 } 711 }
712 712
713 if (!ip6_tnl_rcv_ctl(t)) { 713 if (!ip6_tnl_rcv_ctl(t)) {
714 t->stat.rx_dropped++; 714 t->dev->stats.rx_dropped++;
715 read_unlock(&ip6_tnl_lock); 715 read_unlock(&ip6_tnl_lock);
716 goto discard; 716 goto discard;
717 } 717 }
@@ -728,8 +728,8 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
728 728
729 dscp_ecn_decapsulate(t, ipv6h, skb); 729 dscp_ecn_decapsulate(t, ipv6h, skb);
730 730
731 t->stat.rx_packets++; 731 t->dev->stats.rx_packets++;
732 t->stat.rx_bytes += skb->len; 732 t->dev->stats.rx_bytes += skb->len;
733 netif_rx(skb); 733 netif_rx(skb);
734 read_unlock(&ip6_tnl_lock); 734 read_unlock(&ip6_tnl_lock);
735 return 0; 735 return 0;
@@ -849,7 +849,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
849 __u32 *pmtu) 849 __u32 *pmtu)
850{ 850{
851 struct ip6_tnl *t = netdev_priv(dev); 851 struct ip6_tnl *t = netdev_priv(dev);
852 struct net_device_stats *stats = &t->stat; 852 struct net_device_stats *stats = &t->dev->stats;
853 struct ipv6hdr *ipv6h = ipv6_hdr(skb); 853 struct ipv6hdr *ipv6h = ipv6_hdr(skb);
854 struct ipv6_tel_txoption opt; 854 struct ipv6_tel_txoption opt;
855 struct dst_entry *dst; 855 struct dst_entry *dst;
@@ -1043,11 +1043,11 @@ static int
1043ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) 1043ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
1044{ 1044{
1045 struct ip6_tnl *t = netdev_priv(dev); 1045 struct ip6_tnl *t = netdev_priv(dev);
1046 struct net_device_stats *stats = &t->stat; 1046 struct net_device_stats *stats = &t->dev->stats;
1047 int ret; 1047 int ret;
1048 1048
1049 if (t->recursion++) { 1049 if (t->recursion++) {
1050 t->stat.collisions++; 1050 stats->collisions++;
1051 goto tx_err; 1051 goto tx_err;
1052 } 1052 }
1053 1053
@@ -1289,19 +1289,6 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
1289} 1289}
1290 1290
1291/** 1291/**
1292 * ip6_tnl_get_stats - return the stats for tunnel device
1293 * @dev: virtual device associated with tunnel
1294 *
1295 * Return: stats for device
1296 **/
1297
1298static struct net_device_stats *
1299ip6_tnl_get_stats(struct net_device *dev)
1300{
1301 return &(((struct ip6_tnl *)netdev_priv(dev))->stat);
1302}
1303
1304/**
1305 * ip6_tnl_change_mtu - change mtu manually for tunnel device 1292 * ip6_tnl_change_mtu - change mtu manually for tunnel device
1306 * @dev: virtual device associated with tunnel 1293 * @dev: virtual device associated with tunnel
1307 * @new_mtu: the new mtu 1294 * @new_mtu: the new mtu
@@ -1334,7 +1321,6 @@ static void ip6_tnl_dev_setup(struct net_device *dev)
1334 dev->uninit = ip6_tnl_dev_uninit; 1321 dev->uninit = ip6_tnl_dev_uninit;
1335 dev->destructor = free_netdev; 1322 dev->destructor = free_netdev;
1336 dev->hard_start_xmit = ip6_tnl_xmit; 1323 dev->hard_start_xmit = ip6_tnl_xmit;
1337 dev->get_stats = ip6_tnl_get_stats;
1338 dev->do_ioctl = ip6_tnl_ioctl; 1324 dev->do_ioctl = ip6_tnl_ioctl;
1339 dev->change_mtu = ip6_tnl_change_mtu; 1325 dev->change_mtu = ip6_tnl_change_mtu;
1340 1326
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 2de3c464fe75..bf268b386963 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -388,8 +388,8 @@ static int pim6_rcv(struct sk_buff *skb)
388 skb->ip_summed = 0; 388 skb->ip_summed = 0;
389 skb->pkt_type = PACKET_HOST; 389 skb->pkt_type = PACKET_HOST;
390 dst_release(skb->dst); 390 dst_release(skb->dst);
391 ((struct net_device_stats *)netdev_priv(reg_dev))->rx_bytes += skb->len; 391 reg_dev->stats.rx_bytes += skb->len;
392 ((struct net_device_stats *)netdev_priv(reg_dev))->rx_packets++; 392 reg_dev->stats.rx_packets++;
393 skb->dst = NULL; 393 skb->dst = NULL;
394 nf_reset(skb); 394 nf_reset(skb);
395 netif_rx(skb); 395 netif_rx(skb);
@@ -409,26 +409,20 @@ static struct inet6_protocol pim6_protocol = {
409static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) 409static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
410{ 410{
411 read_lock(&mrt_lock); 411 read_lock(&mrt_lock);
412 ((struct net_device_stats *)netdev_priv(dev))->tx_bytes += skb->len; 412 dev->stats.tx_bytes += skb->len;
413 ((struct net_device_stats *)netdev_priv(dev))->tx_packets++; 413 dev->stats.tx_packets++;
414 ip6mr_cache_report(skb, reg_vif_num, MRT6MSG_WHOLEPKT); 414 ip6mr_cache_report(skb, reg_vif_num, MRT6MSG_WHOLEPKT);
415 read_unlock(&mrt_lock); 415 read_unlock(&mrt_lock);
416 kfree_skb(skb); 416 kfree_skb(skb);
417 return 0; 417 return 0;
418} 418}
419 419
420static struct net_device_stats *reg_vif_get_stats(struct net_device *dev)
421{
422 return (struct net_device_stats *)netdev_priv(dev);
423}
424
425static void reg_vif_setup(struct net_device *dev) 420static void reg_vif_setup(struct net_device *dev)
426{ 421{
427 dev->type = ARPHRD_PIMREG; 422 dev->type = ARPHRD_PIMREG;
428 dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8; 423 dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8;
429 dev->flags = IFF_NOARP; 424 dev->flags = IFF_NOARP;
430 dev->hard_start_xmit = reg_vif_xmit; 425 dev->hard_start_xmit = reg_vif_xmit;
431 dev->get_stats = reg_vif_get_stats;
432 dev->destructor = free_netdev; 426 dev->destructor = free_netdev;
433} 427}
434 428
@@ -436,9 +430,7 @@ static struct net_device *ip6mr_reg_vif(void)
436{ 430{
437 struct net_device *dev; 431 struct net_device *dev;
438 432
439 dev = alloc_netdev(sizeof(struct net_device_stats), "pim6reg", 433 dev = alloc_netdev(0, "pim6reg", reg_vif_setup);
440 reg_vif_setup);
441
442 if (dev == NULL) 434 if (dev == NULL)
443 return NULL; 435 return NULL;
444 436
@@ -1377,8 +1369,8 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi)
1377 if (vif->flags & MIFF_REGISTER) { 1369 if (vif->flags & MIFF_REGISTER) {
1378 vif->pkt_out++; 1370 vif->pkt_out++;
1379 vif->bytes_out += skb->len; 1371 vif->bytes_out += skb->len;
1380 ((struct net_device_stats *)netdev_priv(vif->dev))->tx_bytes += skb->len; 1372 vif->dev->stats.tx_bytes += skb->len;
1381 ((struct net_device_stats *)netdev_priv(vif->dev))->tx_packets++; 1373 vif->dev->stats.tx_packets++;
1382 ip6mr_cache_report(skb, vifi, MRT6MSG_WHOLEPKT); 1374 ip6mr_cache_report(skb, vifi, MRT6MSG_WHOLEPKT);
1383 kfree_skb(skb); 1375 kfree_skb(skb);
1384 return 0; 1376 return 0;
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 6cae5475737e..689dec899c57 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -208,5 +208,17 @@ config IP6_NF_RAW
208 If you want to compile it as a module, say M here and read 208 If you want to compile it as a module, say M here and read
209 <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. 209 <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
210 210
211# security table for MAC policy
212config IP6_NF_SECURITY
213 tristate "Security table"
214 depends on IP6_NF_IPTABLES
215 depends on SECURITY
216 default m if NETFILTER_ADVANCED=n
217 help
218 This option adds a `security' table to iptables, for use
219 with Mandatory Access Control (MAC) policy.
220
221 If unsure, say N.
222
211endmenu 223endmenu
212 224
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index fbf2c14ed887..3f17c948eefb 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
8obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o 8obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
9obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o 9obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
10obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o 10obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
11obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o
11 12
12# objects for l3 independent conntrack 13# objects for l3 independent conntrack
13nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o 14nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 2eff3ae8977d..1b8815f6153d 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -159,7 +159,6 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
159 case IPQ_COPY_META: 159 case IPQ_COPY_META:
160 case IPQ_COPY_NONE: 160 case IPQ_COPY_NONE:
161 size = NLMSG_SPACE(sizeof(*pmsg)); 161 size = NLMSG_SPACE(sizeof(*pmsg));
162 data_len = 0;
163 break; 162 break;
164 163
165 case IPQ_COPY_PACKET: 164 case IPQ_COPY_PACKET:
@@ -226,8 +225,6 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
226 return skb; 225 return skb;
227 226
228nlmsg_failure: 227nlmsg_failure:
229 if (skb)
230 kfree_skb(skb);
231 *errp = -EINVAL; 228 *errp = -EINVAL;
232 printk(KERN_ERR "ip6_queue: error creating packet message\n"); 229 printk(KERN_ERR "ip6_queue: error creating packet message\n");
233 return NULL; 230 return NULL;
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c
new file mode 100644
index 000000000000..063a3d9c3c67
--- /dev/null
+++ b/net/ipv6/netfilter/ip6table_security.c
@@ -0,0 +1,172 @@
1/*
2 * "security" table for IPv6
3 *
4 * This is for use by Mandatory Access Control (MAC) security models,
5 * which need to be able to manage security policy in separate context
6 * to DAC.
7 *
8 * Based on iptable_mangle.c
9 *
10 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
11 * Copyright (C) 2000-2004 Netfilter Core Team <coreteam <at> netfilter.org>
12 * Copyright (C) 2008 Red Hat, Inc., James Morris <jmorris <at> redhat.com>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
17 */
18#include <linux/module.h>
19#include <linux/netfilter_ipv6/ip6_tables.h>
20
21MODULE_LICENSE("GPL");
22MODULE_AUTHOR("James Morris <jmorris <at> redhat.com>");
23MODULE_DESCRIPTION("ip6tables security table, for MAC rules");
24
25#define SECURITY_VALID_HOOKS (1 << NF_INET_LOCAL_IN) | \
26 (1 << NF_INET_FORWARD) | \
27 (1 << NF_INET_LOCAL_OUT)
28
29static struct
30{
31 struct ip6t_replace repl;
32 struct ip6t_standard entries[3];
33 struct ip6t_error term;
34} initial_table __initdata = {
35 .repl = {
36 .name = "security",
37 .valid_hooks = SECURITY_VALID_HOOKS,
38 .num_entries = 4,
39 .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
40 .hook_entry = {
41 [NF_INET_LOCAL_IN] = 0,
42 [NF_INET_FORWARD] = sizeof(struct ip6t_standard),
43 [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2,
44 },
45 .underflow = {
46 [NF_INET_LOCAL_IN] = 0,
47 [NF_INET_FORWARD] = sizeof(struct ip6t_standard),
48 [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2,
49 },
50 },
51 .entries = {
52 IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
53 IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
54 IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
55 },
56 .term = IP6T_ERROR_INIT, /* ERROR */
57};
58
59static struct xt_table security_table = {
60 .name = "security",
61 .valid_hooks = SECURITY_VALID_HOOKS,
62 .lock = __RW_LOCK_UNLOCKED(security_table.lock),
63 .me = THIS_MODULE,
64 .af = AF_INET6,
65};
66
67static unsigned int
68ip6t_local_in_hook(unsigned int hook,
69 struct sk_buff *skb,
70 const struct net_device *in,
71 const struct net_device *out,
72 int (*okfn)(struct sk_buff *))
73{
74 return ip6t_do_table(skb, hook, in, out,
75 init_net.ipv6.ip6table_security);
76}
77
78static unsigned int
79ip6t_forward_hook(unsigned int hook,
80 struct sk_buff *skb,
81 const struct net_device *in,
82 const struct net_device *out,
83 int (*okfn)(struct sk_buff *))
84{
85 return ip6t_do_table(skb, hook, in, out,
86 init_net.ipv6.ip6table_security);
87}
88
89static unsigned int
90ip6t_local_out_hook(unsigned int hook,
91 struct sk_buff *skb,
92 const struct net_device *in,
93 const struct net_device *out,
94 int (*okfn)(struct sk_buff *))
95{
96 /* TBD: handle short packets via raw socket */
97 return ip6t_do_table(skb, hook, in, out,
98 init_net.ipv6.ip6table_security);
99}
100
101static struct nf_hook_ops ip6t_ops[] __read_mostly = {
102 {
103 .hook = ip6t_local_in_hook,
104 .owner = THIS_MODULE,
105 .pf = PF_INET6,
106 .hooknum = NF_INET_LOCAL_IN,
107 .priority = NF_IP6_PRI_SECURITY,
108 },
109 {
110 .hook = ip6t_forward_hook,
111 .owner = THIS_MODULE,
112 .pf = PF_INET6,
113 .hooknum = NF_INET_FORWARD,
114 .priority = NF_IP6_PRI_SECURITY,
115 },
116 {
117 .hook = ip6t_local_out_hook,
118 .owner = THIS_MODULE,
119 .pf = PF_INET6,
120 .hooknum = NF_INET_LOCAL_OUT,
121 .priority = NF_IP6_PRI_SECURITY,
122 },
123};
124
125static int __net_init ip6table_security_net_init(struct net *net)
126{
127 net->ipv6.ip6table_security =
128 ip6t_register_table(net, &security_table, &initial_table.repl);
129
130 if (IS_ERR(net->ipv6.ip6table_security))
131 return PTR_ERR(net->ipv6.ip6table_security);
132
133 return 0;
134}
135
136static void __net_exit ip6table_security_net_exit(struct net *net)
137{
138 ip6t_unregister_table(net->ipv6.ip6table_security);
139}
140
141static struct pernet_operations ip6table_security_net_ops = {
142 .init = ip6table_security_net_init,
143 .exit = ip6table_security_net_exit,
144};
145
146static int __init ip6table_security_init(void)
147{
148 int ret;
149
150 ret = register_pernet_subsys(&ip6table_security_net_ops);
151 if (ret < 0)
152 return ret;
153
154 ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
155 if (ret < 0)
156 goto cleanup_table;
157
158 return ret;
159
160cleanup_table:
161 unregister_pernet_subsys(&ip6table_security_net_ops);
162 return ret;
163}
164
165static void __exit ip6table_security_fini(void)
166{
167 nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
168 unregister_pernet_subsys(&ip6table_security_net_ops);
169}
170
171module_init(ip6table_security_init);
172module_exit(ip6table_security_fini);
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index ee713b03e9ec..14d47d833545 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -89,9 +89,8 @@ static int icmpv6_packet(struct nf_conn *ct,
89 means this will only run once even if count hits zero twice 89 means this will only run once even if count hits zero twice
90 (theoretically possible with SMP) */ 90 (theoretically possible with SMP) */
91 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { 91 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
92 if (atomic_dec_and_test(&ct->proto.icmp.count) 92 if (atomic_dec_and_test(&ct->proto.icmp.count))
93 && del_timer(&ct->timeout)) 93 nf_ct_kill_acct(ct, ctinfo, skb);
94 ct->timeout.function((unsigned long)ct);
95 } else { 94 } else {
96 atomic_inc(&ct->proto.icmp.count); 95 atomic_inc(&ct->proto.icmp.count);
97 nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb); 96 nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 798cabc7535b..9391a6949b96 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -632,7 +632,7 @@ static struct inet6_protocol frag_protocol =
632}; 632};
633 633
634#ifdef CONFIG_SYSCTL 634#ifdef CONFIG_SYSCTL
635static struct ctl_table ip6_frags_ctl_table[] = { 635static struct ctl_table ip6_frags_ns_ctl_table[] = {
636 { 636 {
637 .ctl_name = NET_IPV6_IP6FRAG_HIGH_THRESH, 637 .ctl_name = NET_IPV6_IP6FRAG_HIGH_THRESH,
638 .procname = "ip6frag_high_thresh", 638 .procname = "ip6frag_high_thresh",
@@ -658,6 +658,10 @@ static struct ctl_table ip6_frags_ctl_table[] = {
658 .proc_handler = &proc_dointvec_jiffies, 658 .proc_handler = &proc_dointvec_jiffies,
659 .strategy = &sysctl_jiffies, 659 .strategy = &sysctl_jiffies,
660 }, 660 },
661 { }
662};
663
664static struct ctl_table ip6_frags_ctl_table[] = {
661 { 665 {
662 .ctl_name = NET_IPV6_IP6FRAG_SECRET_INTERVAL, 666 .ctl_name = NET_IPV6_IP6FRAG_SECRET_INTERVAL,
663 .procname = "ip6frag_secret_interval", 667 .procname = "ip6frag_secret_interval",
@@ -670,21 +674,20 @@ static struct ctl_table ip6_frags_ctl_table[] = {
670 { } 674 { }
671}; 675};
672 676
673static int ip6_frags_sysctl_register(struct net *net) 677static int ip6_frags_ns_sysctl_register(struct net *net)
674{ 678{
675 struct ctl_table *table; 679 struct ctl_table *table;
676 struct ctl_table_header *hdr; 680 struct ctl_table_header *hdr;
677 681
678 table = ip6_frags_ctl_table; 682 table = ip6_frags_ns_ctl_table;
679 if (net != &init_net) { 683 if (net != &init_net) {
680 table = kmemdup(table, sizeof(ip6_frags_ctl_table), GFP_KERNEL); 684 table = kmemdup(table, sizeof(ip6_frags_ns_ctl_table), GFP_KERNEL);
681 if (table == NULL) 685 if (table == NULL)
682 goto err_alloc; 686 goto err_alloc;
683 687
684 table[0].data = &net->ipv6.frags.high_thresh; 688 table[0].data = &net->ipv6.frags.high_thresh;
685 table[1].data = &net->ipv6.frags.low_thresh; 689 table[1].data = &net->ipv6.frags.low_thresh;
686 table[2].data = &net->ipv6.frags.timeout; 690 table[2].data = &net->ipv6.frags.timeout;
687 table[3].mode &= ~0222;
688 } 691 }
689 692
690 hdr = register_net_sysctl_table(net, net_ipv6_ctl_path, table); 693 hdr = register_net_sysctl_table(net, net_ipv6_ctl_path, table);
@@ -701,7 +704,7 @@ err_alloc:
701 return -ENOMEM; 704 return -ENOMEM;
702} 705}
703 706
704static void ip6_frags_sysctl_unregister(struct net *net) 707static void ip6_frags_ns_sysctl_unregister(struct net *net)
705{ 708{
706 struct ctl_table *table; 709 struct ctl_table *table;
707 710
@@ -709,13 +712,36 @@ static void ip6_frags_sysctl_unregister(struct net *net)
709 unregister_net_sysctl_table(net->ipv6.sysctl.frags_hdr); 712 unregister_net_sysctl_table(net->ipv6.sysctl.frags_hdr);
710 kfree(table); 713 kfree(table);
711} 714}
715
716static struct ctl_table_header *ip6_ctl_header;
717
718static int ip6_frags_sysctl_register(void)
719{
720 ip6_ctl_header = register_net_sysctl_rotable(net_ipv6_ctl_path,
721 ip6_frags_ctl_table);
722 return ip6_ctl_header == NULL ? -ENOMEM : 0;
723}
724
725static void ip6_frags_sysctl_unregister(void)
726{
727 unregister_net_sysctl_table(ip6_ctl_header);
728}
712#else 729#else
713static inline int ip6_frags_sysctl_register(struct net *net) 730static inline int ip6_frags_ns_sysctl_register(struct net *net)
714{ 731{
715 return 0; 732 return 0;
716} 733}
717 734
718static inline void ip6_frags_sysctl_unregister(struct net *net) 735static inline void ip6_frags_ns_sysctl_unregister(struct net *net)
736{
737}
738
739static inline int ip6_frags_sysctl_register(void)
740{
741 return 0;
742}
743
744static inline void ip6_frags_sysctl_unregister(void)
719{ 745{
720} 746}
721#endif 747#endif
@@ -728,12 +754,12 @@ static int ipv6_frags_init_net(struct net *net)
728 754
729 inet_frags_init_net(&net->ipv6.frags); 755 inet_frags_init_net(&net->ipv6.frags);
730 756
731 return ip6_frags_sysctl_register(net); 757 return ip6_frags_ns_sysctl_register(net);
732} 758}
733 759
734static void ipv6_frags_exit_net(struct net *net) 760static void ipv6_frags_exit_net(struct net *net)
735{ 761{
736 ip6_frags_sysctl_unregister(net); 762 ip6_frags_ns_sysctl_unregister(net);
737 inet_frags_exit_net(&net->ipv6.frags, &ip6_frags); 763 inet_frags_exit_net(&net->ipv6.frags, &ip6_frags);
738} 764}
739 765
@@ -750,7 +776,13 @@ int __init ipv6_frag_init(void)
750 if (ret) 776 if (ret)
751 goto out; 777 goto out;
752 778
753 register_pernet_subsys(&ip6_frags_ops); 779 ret = ip6_frags_sysctl_register();
780 if (ret)
781 goto err_sysctl;
782
783 ret = register_pernet_subsys(&ip6_frags_ops);
784 if (ret)
785 goto err_pernet;
754 786
755 ip6_frags.hashfn = ip6_hashfn; 787 ip6_frags.hashfn = ip6_hashfn;
756 ip6_frags.constructor = ip6_frag_init; 788 ip6_frags.constructor = ip6_frag_init;
@@ -763,11 +795,18 @@ int __init ipv6_frag_init(void)
763 inet_frags_init(&ip6_frags); 795 inet_frags_init(&ip6_frags);
764out: 796out:
765 return ret; 797 return ret;
798
799err_pernet:
800 ip6_frags_sysctl_unregister();
801err_sysctl:
802 inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT);
803 goto out;
766} 804}
767 805
768void ipv6_frag_exit(void) 806void ipv6_frag_exit(void)
769{ 807{
770 inet_frags_fini(&ip6_frags); 808 inet_frags_fini(&ip6_frags);
809 ip6_frags_sysctl_unregister();
771 unregister_pernet_subsys(&ip6_frags_ops); 810 unregister_pernet_subsys(&ip6_frags_ops);
772 inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT); 811 inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT);
773} 812}
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 3de6ffdaedf2..6b8f0583b637 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -491,13 +491,13 @@ static int ipip6_rcv(struct sk_buff *skb)
491 491
492 if ((tunnel->dev->priv_flags & IFF_ISATAP) && 492 if ((tunnel->dev->priv_flags & IFF_ISATAP) &&
493 !isatap_chksrc(skb, iph, tunnel)) { 493 !isatap_chksrc(skb, iph, tunnel)) {
494 tunnel->stat.rx_errors++; 494 tunnel->dev->stats.rx_errors++;
495 read_unlock(&ipip6_lock); 495 read_unlock(&ipip6_lock);
496 kfree_skb(skb); 496 kfree_skb(skb);
497 return 0; 497 return 0;
498 } 498 }
499 tunnel->stat.rx_packets++; 499 tunnel->dev->stats.rx_packets++;
500 tunnel->stat.rx_bytes += skb->len; 500 tunnel->dev->stats.rx_bytes += skb->len;
501 skb->dev = tunnel->dev; 501 skb->dev = tunnel->dev;
502 dst_release(skb->dst); 502 dst_release(skb->dst);
503 skb->dst = NULL; 503 skb->dst = NULL;
@@ -537,7 +537,7 @@ static inline __be32 try_6to4(struct in6_addr *v6dst)
537static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) 537static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
538{ 538{
539 struct ip_tunnel *tunnel = netdev_priv(dev); 539 struct ip_tunnel *tunnel = netdev_priv(dev);
540 struct net_device_stats *stats = &tunnel->stat; 540 struct net_device_stats *stats = &tunnel->dev->stats;
541 struct iphdr *tiph = &tunnel->parms.iph; 541 struct iphdr *tiph = &tunnel->parms.iph;
542 struct ipv6hdr *iph6 = ipv6_hdr(skb); 542 struct ipv6hdr *iph6 = ipv6_hdr(skb);
543 u8 tos = tunnel->parms.iph.tos; 543 u8 tos = tunnel->parms.iph.tos;
@@ -551,7 +551,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
551 int addr_type; 551 int addr_type;
552 552
553 if (tunnel->recursion++) { 553 if (tunnel->recursion++) {
554 tunnel->stat.collisions++; 554 stats->collisions++;
555 goto tx_error; 555 goto tx_error;
556 } 556 }
557 557
@@ -618,20 +618,20 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
618 .oif = tunnel->parms.link, 618 .oif = tunnel->parms.link,
619 .proto = IPPROTO_IPV6 }; 619 .proto = IPPROTO_IPV6 };
620 if (ip_route_output_key(dev_net(dev), &rt, &fl)) { 620 if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
621 tunnel->stat.tx_carrier_errors++; 621 stats->tx_carrier_errors++;
622 goto tx_error_icmp; 622 goto tx_error_icmp;
623 } 623 }
624 } 624 }
625 if (rt->rt_type != RTN_UNICAST) { 625 if (rt->rt_type != RTN_UNICAST) {
626 ip_rt_put(rt); 626 ip_rt_put(rt);
627 tunnel->stat.tx_carrier_errors++; 627 stats->tx_carrier_errors++;
628 goto tx_error_icmp; 628 goto tx_error_icmp;
629 } 629 }
630 tdev = rt->u.dst.dev; 630 tdev = rt->u.dst.dev;
631 631
632 if (tdev == dev) { 632 if (tdev == dev) {
633 ip_rt_put(rt); 633 ip_rt_put(rt);
634 tunnel->stat.collisions++; 634 stats->collisions++;
635 goto tx_error; 635 goto tx_error;
636 } 636 }
637 637
@@ -641,7 +641,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
641 mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu; 641 mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
642 642
643 if (mtu < 68) { 643 if (mtu < 68) {
644 tunnel->stat.collisions++; 644 stats->collisions++;
645 ip_rt_put(rt); 645 ip_rt_put(rt);
646 goto tx_error; 646 goto tx_error;
647 } 647 }
@@ -916,11 +916,6 @@ done:
916 return err; 916 return err;
917} 917}
918 918
919static struct net_device_stats *ipip6_tunnel_get_stats(struct net_device *dev)
920{
921 return &(((struct ip_tunnel*)netdev_priv(dev))->stat);
922}
923
924static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu) 919static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu)
925{ 920{
926 if (new_mtu < IPV6_MIN_MTU || new_mtu > 0xFFF8 - sizeof(struct iphdr)) 921 if (new_mtu < IPV6_MIN_MTU || new_mtu > 0xFFF8 - sizeof(struct iphdr))
@@ -934,7 +929,6 @@ static void ipip6_tunnel_setup(struct net_device *dev)
934 dev->uninit = ipip6_tunnel_uninit; 929 dev->uninit = ipip6_tunnel_uninit;
935 dev->destructor = free_netdev; 930 dev->destructor = free_netdev;
936 dev->hard_start_xmit = ipip6_tunnel_xmit; 931 dev->hard_start_xmit = ipip6_tunnel_xmit;
937 dev->get_stats = ipip6_tunnel_get_stats;
938 dev->do_ioctl = ipip6_tunnel_ioctl; 932 dev->do_ioctl = ipip6_tunnel_ioctl;
939 dev->change_mtu = ipip6_tunnel_change_mtu; 933 dev->change_mtu = ipip6_tunnel_change_mtu;
940 934
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index 3804dcbbfab0..5c99274558bf 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -37,6 +37,10 @@ static ctl_table ipv6_table_template[] = {
37 .mode = 0644, 37 .mode = 0644,
38 .proc_handler = &proc_dointvec 38 .proc_handler = &proc_dointvec
39 }, 39 },
40 { .ctl_name = 0 }
41};
42
43static ctl_table ipv6_table[] = {
40 { 44 {
41 .ctl_name = NET_IPV6_MLD_MAX_MSF, 45 .ctl_name = NET_IPV6_MLD_MAX_MSF,
42 .procname = "mld_max_msf", 46 .procname = "mld_max_msf",
@@ -80,12 +84,6 @@ static int ipv6_sysctl_net_init(struct net *net)
80 84
81 ipv6_table[2].data = &net->ipv6.sysctl.bindv6only; 85 ipv6_table[2].data = &net->ipv6.sysctl.bindv6only;
82 86
83 /* We don't want this value to be per namespace, it should be global
84 to all namespaces, so make it read-only when we are not in the
85 init network namespace */
86 if (net != &init_net)
87 ipv6_table[3].mode = 0444;
88
89 net->ipv6.sysctl.table = register_net_sysctl_table(net, net_ipv6_ctl_path, 87 net->ipv6.sysctl.table = register_net_sysctl_table(net, net_ipv6_ctl_path,
90 ipv6_table); 88 ipv6_table);
91 if (!net->ipv6.sysctl.table) 89 if (!net->ipv6.sysctl.table)
@@ -126,12 +124,29 @@ static struct pernet_operations ipv6_sysctl_net_ops = {
126 .exit = ipv6_sysctl_net_exit, 124 .exit = ipv6_sysctl_net_exit,
127}; 125};
128 126
127static struct ctl_table_header *ip6_header;
128
129int ipv6_sysctl_register(void) 129int ipv6_sysctl_register(void)
130{ 130{
131 return register_pernet_subsys(&ipv6_sysctl_net_ops); 131 int err = -ENOMEM;;
132
133 ip6_header = register_net_sysctl_rotable(net_ipv6_ctl_path, ipv6_table);
134 if (ip6_header == NULL)
135 goto out;
136
137 err = register_pernet_subsys(&ipv6_sysctl_net_ops);
138 if (err)
139 goto err_pernet;
140out:
141 return err;
142
143err_pernet:
144 unregister_net_sysctl_table(ip6_header);
145 goto out;
132} 146}
133 147
134void ipv6_sysctl_unregister(void) 148void ipv6_sysctl_unregister(void)
135{ 149{
150 unregister_net_sysctl_table(ip6_header);
136 unregister_pernet_subsys(&ipv6_sysctl_net_ops); 151 unregister_pernet_subsys(&ipv6_sysctl_net_ops);
137} 152}