Merge tag 'net-5.18-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[platform/kernel/linux-starfive.git] / net / ipv6 / sysctl_net_ipv6.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * sysctl_net_ipv6.c: sysctl interface to net IPV6 subsystem.
4  *
5  * Changes:
6  * YOSHIFUJI Hideaki @USAGI:    added icmp sysctl table.
7  */
8
9 #include <linux/mm.h>
10 #include <linux/sysctl.h>
11 #include <linux/in6.h>
12 #include <linux/ipv6.h>
13 #include <linux/slab.h>
14 #include <linux/export.h>
15 #include <net/ndisc.h>
16 #include <net/ipv6.h>
17 #include <net/addrconf.h>
18 #include <net/inet_frag.h>
19 #include <net/netevent.h>
20 #include <net/ip_fib.h>
21 #ifdef CONFIG_NETLABEL
22 #include <net/calipso.h>
23 #endif
24 #include <linux/ioam6.h>
25
26 static int two = 2;
27 static int three = 3;
28 static int flowlabel_reflect_max = 0x7;
29 static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX;
30 static u32 rt6_multipath_hash_fields_all_mask =
31         FIB_MULTIPATH_HASH_FIELD_ALL_MASK;
32 static u32 ioam6_id_max = IOAM6_DEFAULT_ID;
33 static u64 ioam6_id_wide_max = IOAM6_DEFAULT_ID_WIDE;
34
35 static int proc_rt6_multipath_hash_policy(struct ctl_table *table, int write,
36                                           void *buffer, size_t *lenp, loff_t *ppos)
37 {
38         struct net *net;
39         int ret;
40
41         net = container_of(table->data, struct net,
42                            ipv6.sysctl.multipath_hash_policy);
43         ret = proc_dou8vec_minmax(table, write, buffer, lenp, ppos);
44         if (write && ret == 0)
45                 call_netevent_notifiers(NETEVENT_IPV6_MPATH_HASH_UPDATE, net);
46
47         return ret;
48 }
49
50 static int
51 proc_rt6_multipath_hash_fields(struct ctl_table *table, int write, void *buffer,
52                                size_t *lenp, loff_t *ppos)
53 {
54         struct net *net;
55         int ret;
56
57         net = container_of(table->data, struct net,
58                            ipv6.sysctl.multipath_hash_fields);
59         ret = proc_douintvec_minmax(table, write, buffer, lenp, ppos);
60         if (write && ret == 0)
61                 call_netevent_notifiers(NETEVENT_IPV6_MPATH_HASH_UPDATE, net);
62
63         return ret;
64 }
65
66 static struct ctl_table ipv6_table_template[] = {
67         {
68                 .procname       = "bindv6only",
69                 .data           = &init_net.ipv6.sysctl.bindv6only,
70                 .maxlen         = sizeof(u8),
71                 .mode           = 0644,
72                 .proc_handler   = proc_dou8vec_minmax,
73         },
74         {
75                 .procname       = "anycast_src_echo_reply",
76                 .data           = &init_net.ipv6.sysctl.anycast_src_echo_reply,
77                 .maxlen         = sizeof(u8),
78                 .mode           = 0644,
79                 .proc_handler   = proc_dou8vec_minmax,
80         },
81         {
82                 .procname       = "flowlabel_consistency",
83                 .data           = &init_net.ipv6.sysctl.flowlabel_consistency,
84                 .maxlen         = sizeof(u8),
85                 .mode           = 0644,
86                 .proc_handler   = proc_dou8vec_minmax,
87         },
88         {
89                 .procname       = "auto_flowlabels",
90                 .data           = &init_net.ipv6.sysctl.auto_flowlabels,
91                 .maxlen         = sizeof(u8),
92                 .mode           = 0644,
93                 .proc_handler   = proc_dou8vec_minmax,
94                 .extra2         = &auto_flowlabels_max
95         },
96         {
97                 .procname       = "fwmark_reflect",
98                 .data           = &init_net.ipv6.sysctl.fwmark_reflect,
99                 .maxlen         = sizeof(u8),
100                 .mode           = 0644,
101                 .proc_handler   = proc_dou8vec_minmax,
102         },
103         {
104                 .procname       = "idgen_retries",
105                 .data           = &init_net.ipv6.sysctl.idgen_retries,
106                 .maxlen         = sizeof(int),
107                 .mode           = 0644,
108                 .proc_handler   = proc_dointvec,
109         },
110         {
111                 .procname       = "idgen_delay",
112                 .data           = &init_net.ipv6.sysctl.idgen_delay,
113                 .maxlen         = sizeof(int),
114                 .mode           = 0644,
115                 .proc_handler   = proc_dointvec_jiffies,
116         },
117         {
118                 .procname       = "flowlabel_state_ranges",
119                 .data           = &init_net.ipv6.sysctl.flowlabel_state_ranges,
120                 .maxlen         = sizeof(u8),
121                 .mode           = 0644,
122                 .proc_handler   = proc_dou8vec_minmax,
123         },
124         {
125                 .procname       = "ip_nonlocal_bind",
126                 .data           = &init_net.ipv6.sysctl.ip_nonlocal_bind,
127                 .maxlen         = sizeof(u8),
128                 .mode           = 0644,
129                 .proc_handler   = proc_dou8vec_minmax,
130         },
131         {
132                 .procname       = "flowlabel_reflect",
133                 .data           = &init_net.ipv6.sysctl.flowlabel_reflect,
134                 .maxlen         = sizeof(int),
135                 .mode           = 0644,
136                 .proc_handler   = proc_dointvec_minmax,
137                 .extra1         = SYSCTL_ZERO,
138                 .extra2         = &flowlabel_reflect_max,
139         },
140         {
141                 .procname       = "max_dst_opts_number",
142                 .data           = &init_net.ipv6.sysctl.max_dst_opts_cnt,
143                 .maxlen         = sizeof(int),
144                 .mode           = 0644,
145                 .proc_handler   = proc_dointvec
146         },
147         {
148                 .procname       = "max_hbh_opts_number",
149                 .data           = &init_net.ipv6.sysctl.max_hbh_opts_cnt,
150                 .maxlen         = sizeof(int),
151                 .mode           = 0644,
152                 .proc_handler   = proc_dointvec
153         },
154         {
155                 .procname       = "max_dst_opts_length",
156                 .data           = &init_net.ipv6.sysctl.max_dst_opts_len,
157                 .maxlen         = sizeof(int),
158                 .mode           = 0644,
159                 .proc_handler   = proc_dointvec
160         },
161         {
162                 .procname       = "max_hbh_length",
163                 .data           = &init_net.ipv6.sysctl.max_hbh_opts_len,
164                 .maxlen         = sizeof(int),
165                 .mode           = 0644,
166                 .proc_handler   = proc_dointvec
167         },
168         {
169                 .procname       = "fib_multipath_hash_policy",
170                 .data           = &init_net.ipv6.sysctl.multipath_hash_policy,
171                 .maxlen         = sizeof(u8),
172                 .mode           = 0644,
173                 .proc_handler   = proc_rt6_multipath_hash_policy,
174                 .extra1         = SYSCTL_ZERO,
175                 .extra2         = &three,
176         },
177         {
178                 .procname       = "fib_multipath_hash_fields",
179                 .data           = &init_net.ipv6.sysctl.multipath_hash_fields,
180                 .maxlen         = sizeof(u32),
181                 .mode           = 0644,
182                 .proc_handler   = proc_rt6_multipath_hash_fields,
183                 .extra1         = SYSCTL_ONE,
184                 .extra2         = &rt6_multipath_hash_fields_all_mask,
185         },
186         {
187                 .procname       = "seg6_flowlabel",
188                 .data           = &init_net.ipv6.sysctl.seg6_flowlabel,
189                 .maxlen         = sizeof(int),
190                 .mode           = 0644,
191                 .proc_handler   = proc_dointvec
192         },
193         {
194                 .procname       = "fib_notify_on_flag_change",
195                 .data           = &init_net.ipv6.sysctl.fib_notify_on_flag_change,
196                 .maxlen         = sizeof(u8),
197                 .mode           = 0644,
198                 .proc_handler   = proc_dou8vec_minmax,
199                 .extra1         = SYSCTL_ZERO,
200                 .extra2         = &two,
201         },
202         {
203                 .procname       = "ioam6_id",
204                 .data           = &init_net.ipv6.sysctl.ioam6_id,
205                 .maxlen         = sizeof(u32),
206                 .mode           = 0644,
207                 .proc_handler   = proc_douintvec_minmax,
208                 .extra2         = &ioam6_id_max,
209         },
210         {
211                 .procname       = "ioam6_id_wide",
212                 .data           = &init_net.ipv6.sysctl.ioam6_id_wide,
213                 .maxlen         = sizeof(u64),
214                 .mode           = 0644,
215                 .proc_handler   = proc_doulongvec_minmax,
216                 .extra2         = &ioam6_id_wide_max,
217         },
218         { }
219 };
220
221 static struct ctl_table ipv6_rotable[] = {
222         {
223                 .procname       = "mld_max_msf",
224                 .data           = &sysctl_mld_max_msf,
225                 .maxlen         = sizeof(int),
226                 .mode           = 0644,
227                 .proc_handler   = proc_dointvec
228         },
229         {
230                 .procname       = "mld_qrv",
231                 .data           = &sysctl_mld_qrv,
232                 .maxlen         = sizeof(int),
233                 .mode           = 0644,
234                 .proc_handler   = proc_dointvec_minmax,
235                 .extra1         = SYSCTL_ONE
236         },
237 #ifdef CONFIG_NETLABEL
238         {
239                 .procname       = "calipso_cache_enable",
240                 .data           = &calipso_cache_enabled,
241                 .maxlen         = sizeof(int),
242                 .mode           = 0644,
243                 .proc_handler   = proc_dointvec,
244         },
245         {
246                 .procname       = "calipso_cache_bucket_size",
247                 .data           = &calipso_cache_bucketsize,
248                 .maxlen         = sizeof(int),
249                 .mode           = 0644,
250                 .proc_handler   = proc_dointvec,
251         },
252 #endif /* CONFIG_NETLABEL */
253         { }
254 };
255
256 static int __net_init ipv6_sysctl_net_init(struct net *net)
257 {
258         struct ctl_table *ipv6_table;
259         struct ctl_table *ipv6_route_table;
260         struct ctl_table *ipv6_icmp_table;
261         int err, i;
262
263         err = -ENOMEM;
264         ipv6_table = kmemdup(ipv6_table_template, sizeof(ipv6_table_template),
265                              GFP_KERNEL);
266         if (!ipv6_table)
267                 goto out;
268         /* Update the variables to point into the current struct net */
269         for (i = 0; i < ARRAY_SIZE(ipv6_table_template) - 1; i++)
270                 ipv6_table[i].data += (void *)net - (void *)&init_net;
271
272         ipv6_route_table = ipv6_route_sysctl_init(net);
273         if (!ipv6_route_table)
274                 goto out_ipv6_table;
275
276         ipv6_icmp_table = ipv6_icmp_sysctl_init(net);
277         if (!ipv6_icmp_table)
278                 goto out_ipv6_route_table;
279
280         net->ipv6.sysctl.hdr = register_net_sysctl(net, "net/ipv6", ipv6_table);
281         if (!net->ipv6.sysctl.hdr)
282                 goto out_ipv6_icmp_table;
283
284         net->ipv6.sysctl.route_hdr =
285                 register_net_sysctl(net, "net/ipv6/route", ipv6_route_table);
286         if (!net->ipv6.sysctl.route_hdr)
287                 goto out_unregister_ipv6_table;
288
289         net->ipv6.sysctl.icmp_hdr =
290                 register_net_sysctl(net, "net/ipv6/icmp", ipv6_icmp_table);
291         if (!net->ipv6.sysctl.icmp_hdr)
292                 goto out_unregister_route_table;
293
294         err = 0;
295 out:
296         return err;
297 out_unregister_route_table:
298         unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr);
299 out_unregister_ipv6_table:
300         unregister_net_sysctl_table(net->ipv6.sysctl.hdr);
301 out_ipv6_icmp_table:
302         kfree(ipv6_icmp_table);
303 out_ipv6_route_table:
304         kfree(ipv6_route_table);
305 out_ipv6_table:
306         kfree(ipv6_table);
307         goto out;
308 }
309
310 static void __net_exit ipv6_sysctl_net_exit(struct net *net)
311 {
312         struct ctl_table *ipv6_table;
313         struct ctl_table *ipv6_route_table;
314         struct ctl_table *ipv6_icmp_table;
315
316         ipv6_table = net->ipv6.sysctl.hdr->ctl_table_arg;
317         ipv6_route_table = net->ipv6.sysctl.route_hdr->ctl_table_arg;
318         ipv6_icmp_table = net->ipv6.sysctl.icmp_hdr->ctl_table_arg;
319
320         unregister_net_sysctl_table(net->ipv6.sysctl.icmp_hdr);
321         unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr);
322         unregister_net_sysctl_table(net->ipv6.sysctl.hdr);
323
324         kfree(ipv6_table);
325         kfree(ipv6_route_table);
326         kfree(ipv6_icmp_table);
327 }
328
329 static struct pernet_operations ipv6_sysctl_net_ops = {
330         .init = ipv6_sysctl_net_init,
331         .exit = ipv6_sysctl_net_exit,
332 };
333
334 static struct ctl_table_header *ip6_header;
335
336 int ipv6_sysctl_register(void)
337 {
338         int err = -ENOMEM;
339
340         ip6_header = register_net_sysctl(&init_net, "net/ipv6", ipv6_rotable);
341         if (!ip6_header)
342                 goto out;
343
344         err = register_pernet_subsys(&ipv6_sysctl_net_ops);
345         if (err)
346                 goto err_pernet;
347 out:
348         return err;
349
350 err_pernet:
351         unregister_net_sysctl_table(ip6_header);
352         goto out;
353 }
354
355 void ipv6_sysctl_unregister(void)
356 {
357         unregister_net_sysctl_table(ip6_header);
358         unregister_pernet_subsys(&ipv6_sysctl_net_ops);
359 }