xref: /linux/net/ipv6/sysctl_net_ipv6.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
1 /*
2  * sysctl_net_ipv6.c: sysctl interface to net IPV6 subsystem.
3  *
4  * Changes:
5  * YOSHIFUJI Hideaki @USAGI:	added icmp sysctl table.
6  */
7 
8 #include <linux/mm.h>
9 #include <linux/sysctl.h>
10 #include <linux/in6.h>
11 #include <linux/ipv6.h>
12 #include <linux/slab.h>
13 #include <linux/export.h>
14 #include <net/ndisc.h>
15 #include <net/ipv6.h>
16 #include <net/addrconf.h>
17 #include <net/inet_frag.h>
18 
19 static int one = 1;
20 static int auto_flowlabels_min;
21 static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX;
22 
23 
24 static struct ctl_table ipv6_table_template[] = {
25 	{
26 		.procname	= "bindv6only",
27 		.data		= &init_net.ipv6.sysctl.bindv6only,
28 		.maxlen		= sizeof(int),
29 		.mode		= 0644,
30 		.proc_handler	= proc_dointvec
31 	},
32 	{
33 		.procname	= "anycast_src_echo_reply",
34 		.data		= &init_net.ipv6.sysctl.anycast_src_echo_reply,
35 		.maxlen		= sizeof(int),
36 		.mode		= 0644,
37 		.proc_handler	= proc_dointvec
38 	},
39 	{
40 		.procname	= "flowlabel_consistency",
41 		.data		= &init_net.ipv6.sysctl.flowlabel_consistency,
42 		.maxlen		= sizeof(int),
43 		.mode		= 0644,
44 		.proc_handler	= proc_dointvec
45 	},
46 	{
47 		.procname	= "auto_flowlabels",
48 		.data		= &init_net.ipv6.sysctl.auto_flowlabels,
49 		.maxlen		= sizeof(int),
50 		.mode		= 0644,
51 		.proc_handler	= proc_dointvec_minmax,
52 		.extra1		= &auto_flowlabels_min,
53 		.extra2		= &auto_flowlabels_max
54 	},
55 	{
56 		.procname	= "fwmark_reflect",
57 		.data		= &init_net.ipv6.sysctl.fwmark_reflect,
58 		.maxlen		= sizeof(int),
59 		.mode		= 0644,
60 		.proc_handler	= proc_dointvec
61 	},
62 	{
63 		.procname	= "idgen_retries",
64 		.data		= &init_net.ipv6.sysctl.idgen_retries,
65 		.maxlen		= sizeof(int),
66 		.mode		= 0644,
67 		.proc_handler	= proc_dointvec,
68 	},
69 	{
70 		.procname	= "idgen_delay",
71 		.data		= &init_net.ipv6.sysctl.idgen_delay,
72 		.maxlen		= sizeof(int),
73 		.mode		= 0644,
74 		.proc_handler	= proc_dointvec_jiffies,
75 	},
76 	{
77 		.procname	= "flowlabel_state_ranges",
78 		.data		= &init_net.ipv6.sysctl.flowlabel_state_ranges,
79 		.maxlen		= sizeof(int),
80 		.mode		= 0644,
81 		.proc_handler	= proc_dointvec
82 	},
83 	{
84 		.procname	= "ip_nonlocal_bind",
85 		.data		= &init_net.ipv6.sysctl.ip_nonlocal_bind,
86 		.maxlen		= sizeof(int),
87 		.mode		= 0644,
88 		.proc_handler	= proc_dointvec
89 	},
90 	{ }
91 };
92 
93 static struct ctl_table ipv6_rotable[] = {
94 	{
95 		.procname	= "mld_max_msf",
96 		.data		= &sysctl_mld_max_msf,
97 		.maxlen		= sizeof(int),
98 		.mode		= 0644,
99 		.proc_handler	= proc_dointvec
100 	},
101 	{
102 		.procname	= "mld_qrv",
103 		.data		= &sysctl_mld_qrv,
104 		.maxlen		= sizeof(int),
105 		.mode		= 0644,
106 		.proc_handler	= proc_dointvec_minmax,
107 		.extra1		= &one
108 	},
109 	{ }
110 };
111 
112 static int __net_init ipv6_sysctl_net_init(struct net *net)
113 {
114 	struct ctl_table *ipv6_table;
115 	struct ctl_table *ipv6_route_table;
116 	struct ctl_table *ipv6_icmp_table;
117 	int err;
118 
119 	err = -ENOMEM;
120 	ipv6_table = kmemdup(ipv6_table_template, sizeof(ipv6_table_template),
121 			     GFP_KERNEL);
122 	if (!ipv6_table)
123 		goto out;
124 	ipv6_table[0].data = &net->ipv6.sysctl.bindv6only;
125 	ipv6_table[1].data = &net->ipv6.sysctl.anycast_src_echo_reply;
126 	ipv6_table[2].data = &net->ipv6.sysctl.flowlabel_consistency;
127 	ipv6_table[3].data = &net->ipv6.sysctl.auto_flowlabels;
128 	ipv6_table[4].data = &net->ipv6.sysctl.fwmark_reflect;
129 	ipv6_table[5].data = &net->ipv6.sysctl.idgen_retries;
130 	ipv6_table[6].data = &net->ipv6.sysctl.idgen_delay;
131 	ipv6_table[7].data = &net->ipv6.sysctl.flowlabel_state_ranges;
132 	ipv6_table[8].data = &net->ipv6.sysctl.ip_nonlocal_bind;
133 
134 	ipv6_route_table = ipv6_route_sysctl_init(net);
135 	if (!ipv6_route_table)
136 		goto out_ipv6_table;
137 
138 	ipv6_icmp_table = ipv6_icmp_sysctl_init(net);
139 	if (!ipv6_icmp_table)
140 		goto out_ipv6_route_table;
141 
142 	net->ipv6.sysctl.hdr = register_net_sysctl(net, "net/ipv6", ipv6_table);
143 	if (!net->ipv6.sysctl.hdr)
144 		goto out_ipv6_icmp_table;
145 
146 	net->ipv6.sysctl.route_hdr =
147 		register_net_sysctl(net, "net/ipv6/route", ipv6_route_table);
148 	if (!net->ipv6.sysctl.route_hdr)
149 		goto out_unregister_ipv6_table;
150 
151 	net->ipv6.sysctl.icmp_hdr =
152 		register_net_sysctl(net, "net/ipv6/icmp", ipv6_icmp_table);
153 	if (!net->ipv6.sysctl.icmp_hdr)
154 		goto out_unregister_route_table;
155 
156 	err = 0;
157 out:
158 	return err;
159 out_unregister_route_table:
160 	unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr);
161 out_unregister_ipv6_table:
162 	unregister_net_sysctl_table(net->ipv6.sysctl.hdr);
163 out_ipv6_icmp_table:
164 	kfree(ipv6_icmp_table);
165 out_ipv6_route_table:
166 	kfree(ipv6_route_table);
167 out_ipv6_table:
168 	kfree(ipv6_table);
169 	goto out;
170 }
171 
172 static void __net_exit ipv6_sysctl_net_exit(struct net *net)
173 {
174 	struct ctl_table *ipv6_table;
175 	struct ctl_table *ipv6_route_table;
176 	struct ctl_table *ipv6_icmp_table;
177 
178 	ipv6_table = net->ipv6.sysctl.hdr->ctl_table_arg;
179 	ipv6_route_table = net->ipv6.sysctl.route_hdr->ctl_table_arg;
180 	ipv6_icmp_table = net->ipv6.sysctl.icmp_hdr->ctl_table_arg;
181 
182 	unregister_net_sysctl_table(net->ipv6.sysctl.icmp_hdr);
183 	unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr);
184 	unregister_net_sysctl_table(net->ipv6.sysctl.hdr);
185 
186 	kfree(ipv6_table);
187 	kfree(ipv6_route_table);
188 	kfree(ipv6_icmp_table);
189 }
190 
191 static struct pernet_operations ipv6_sysctl_net_ops = {
192 	.init = ipv6_sysctl_net_init,
193 	.exit = ipv6_sysctl_net_exit,
194 };
195 
196 static struct ctl_table_header *ip6_header;
197 
198 int ipv6_sysctl_register(void)
199 {
200 	int err = -ENOMEM;
201 
202 	ip6_header = register_net_sysctl(&init_net, "net/ipv6", ipv6_rotable);
203 	if (!ip6_header)
204 		goto out;
205 
206 	err = register_pernet_subsys(&ipv6_sysctl_net_ops);
207 	if (err)
208 		goto err_pernet;
209 out:
210 	return err;
211 
212 err_pernet:
213 	unregister_net_sysctl_table(ip6_header);
214 	goto out;
215 }
216 
217 void ipv6_sysctl_unregister(void)
218 {
219 	unregister_net_sysctl_table(ip6_header);
220 	unregister_pernet_subsys(&ipv6_sysctl_net_ops);
221 }
222