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 #ifdef CONFIG_NETLABEL 21 #include <net/calipso.h> 22 #endif 23 24 static int two = 2; 25 static int flowlabel_reflect_max = 0x7; 26 static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX; 27 28 static int proc_rt6_multipath_hash_policy(struct ctl_table *table, int write, 29 void *buffer, size_t *lenp, loff_t *ppos) 30 { 31 struct net *net; 32 int ret; 33 34 net = container_of(table->data, struct net, 35 ipv6.sysctl.multipath_hash_policy); 36 ret = proc_dou8vec_minmax(table, write, buffer, lenp, ppos); 37 if (write && ret == 0) 38 call_netevent_notifiers(NETEVENT_IPV6_MPATH_HASH_UPDATE, net); 39 40 return ret; 41 } 42 43 static struct ctl_table ipv6_table_template[] = { 44 { 45 .procname = "bindv6only", 46 .data = &init_net.ipv6.sysctl.bindv6only, 47 .maxlen = sizeof(u8), 48 .mode = 0644, 49 .proc_handler = proc_dou8vec_minmax, 50 }, 51 { 52 .procname = "anycast_src_echo_reply", 53 .data = &init_net.ipv6.sysctl.anycast_src_echo_reply, 54 .maxlen = sizeof(u8), 55 .mode = 0644, 56 .proc_handler = proc_dou8vec_minmax, 57 }, 58 { 59 .procname = "flowlabel_consistency", 60 .data = &init_net.ipv6.sysctl.flowlabel_consistency, 61 .maxlen = sizeof(u8), 62 .mode = 0644, 63 .proc_handler = proc_dou8vec_minmax, 64 }, 65 { 66 .procname = "auto_flowlabels", 67 .data = &init_net.ipv6.sysctl.auto_flowlabels, 68 .maxlen = sizeof(u8), 69 .mode = 0644, 70 .proc_handler = proc_dou8vec_minmax, 71 .extra2 = &auto_flowlabels_max 72 }, 73 { 74 .procname = "fwmark_reflect", 75 .data = &init_net.ipv6.sysctl.fwmark_reflect, 76 .maxlen = sizeof(u8), 77 .mode = 0644, 78 .proc_handler = proc_dou8vec_minmax, 79 }, 80 { 81 .procname = "idgen_retries", 82 .data = &init_net.ipv6.sysctl.idgen_retries, 83 .maxlen = sizeof(int), 84 .mode = 0644, 85 .proc_handler = proc_dointvec, 86 }, 87 { 88 .procname = "idgen_delay", 89 .data = &init_net.ipv6.sysctl.idgen_delay, 90 .maxlen = sizeof(int), 91 .mode = 0644, 92 .proc_handler = proc_dointvec_jiffies, 93 }, 94 { 95 .procname = "flowlabel_state_ranges", 96 .data = &init_net.ipv6.sysctl.flowlabel_state_ranges, 97 .maxlen = sizeof(u8), 98 .mode = 0644, 99 .proc_handler = proc_dou8vec_minmax, 100 }, 101 { 102 .procname = "ip_nonlocal_bind", 103 .data = &init_net.ipv6.sysctl.ip_nonlocal_bind, 104 .maxlen = sizeof(u8), 105 .mode = 0644, 106 .proc_handler = proc_dou8vec_minmax, 107 }, 108 { 109 .procname = "flowlabel_reflect", 110 .data = &init_net.ipv6.sysctl.flowlabel_reflect, 111 .maxlen = sizeof(int), 112 .mode = 0644, 113 .proc_handler = proc_dointvec_minmax, 114 .extra1 = SYSCTL_ZERO, 115 .extra2 = &flowlabel_reflect_max, 116 }, 117 { 118 .procname = "max_dst_opts_number", 119 .data = &init_net.ipv6.sysctl.max_dst_opts_cnt, 120 .maxlen = sizeof(int), 121 .mode = 0644, 122 .proc_handler = proc_dointvec 123 }, 124 { 125 .procname = "max_hbh_opts_number", 126 .data = &init_net.ipv6.sysctl.max_hbh_opts_cnt, 127 .maxlen = sizeof(int), 128 .mode = 0644, 129 .proc_handler = proc_dointvec 130 }, 131 { 132 .procname = "max_dst_opts_length", 133 .data = &init_net.ipv6.sysctl.max_dst_opts_len, 134 .maxlen = sizeof(int), 135 .mode = 0644, 136 .proc_handler = proc_dointvec 137 }, 138 { 139 .procname = "max_hbh_length", 140 .data = &init_net.ipv6.sysctl.max_hbh_opts_len, 141 .maxlen = sizeof(int), 142 .mode = 0644, 143 .proc_handler = proc_dointvec 144 }, 145 { 146 .procname = "fib_multipath_hash_policy", 147 .data = &init_net.ipv6.sysctl.multipath_hash_policy, 148 .maxlen = sizeof(u8), 149 .mode = 0644, 150 .proc_handler = proc_rt6_multipath_hash_policy, 151 .extra1 = SYSCTL_ZERO, 152 .extra2 = &two, 153 }, 154 { 155 .procname = "seg6_flowlabel", 156 .data = &init_net.ipv6.sysctl.seg6_flowlabel, 157 .maxlen = sizeof(int), 158 .mode = 0644, 159 .proc_handler = proc_dointvec 160 }, 161 { 162 .procname = "fib_notify_on_flag_change", 163 .data = &init_net.ipv6.sysctl.fib_notify_on_flag_change, 164 .maxlen = sizeof(u8), 165 .mode = 0644, 166 .proc_handler = proc_dou8vec_minmax, 167 .extra1 = SYSCTL_ZERO, 168 .extra2 = &two, 169 }, 170 { } 171 }; 172 173 static struct ctl_table ipv6_rotable[] = { 174 { 175 .procname = "mld_max_msf", 176 .data = &sysctl_mld_max_msf, 177 .maxlen = sizeof(int), 178 .mode = 0644, 179 .proc_handler = proc_dointvec 180 }, 181 { 182 .procname = "mld_qrv", 183 .data = &sysctl_mld_qrv, 184 .maxlen = sizeof(int), 185 .mode = 0644, 186 .proc_handler = proc_dointvec_minmax, 187 .extra1 = SYSCTL_ONE 188 }, 189 #ifdef CONFIG_NETLABEL 190 { 191 .procname = "calipso_cache_enable", 192 .data = &calipso_cache_enabled, 193 .maxlen = sizeof(int), 194 .mode = 0644, 195 .proc_handler = proc_dointvec, 196 }, 197 { 198 .procname = "calipso_cache_bucket_size", 199 .data = &calipso_cache_bucketsize, 200 .maxlen = sizeof(int), 201 .mode = 0644, 202 .proc_handler = proc_dointvec, 203 }, 204 #endif /* CONFIG_NETLABEL */ 205 { } 206 }; 207 208 static int __net_init ipv6_sysctl_net_init(struct net *net) 209 { 210 struct ctl_table *ipv6_table; 211 struct ctl_table *ipv6_route_table; 212 struct ctl_table *ipv6_icmp_table; 213 int err, i; 214 215 err = -ENOMEM; 216 ipv6_table = kmemdup(ipv6_table_template, sizeof(ipv6_table_template), 217 GFP_KERNEL); 218 if (!ipv6_table) 219 goto out; 220 /* Update the variables to point into the current struct net */ 221 for (i = 0; i < ARRAY_SIZE(ipv6_table_template) - 1; i++) 222 ipv6_table[i].data += (void *)net - (void *)&init_net; 223 224 ipv6_route_table = ipv6_route_sysctl_init(net); 225 if (!ipv6_route_table) 226 goto out_ipv6_table; 227 228 ipv6_icmp_table = ipv6_icmp_sysctl_init(net); 229 if (!ipv6_icmp_table) 230 goto out_ipv6_route_table; 231 232 net->ipv6.sysctl.hdr = register_net_sysctl(net, "net/ipv6", ipv6_table); 233 if (!net->ipv6.sysctl.hdr) 234 goto out_ipv6_icmp_table; 235 236 net->ipv6.sysctl.route_hdr = 237 register_net_sysctl(net, "net/ipv6/route", ipv6_route_table); 238 if (!net->ipv6.sysctl.route_hdr) 239 goto out_unregister_ipv6_table; 240 241 net->ipv6.sysctl.icmp_hdr = 242 register_net_sysctl(net, "net/ipv6/icmp", ipv6_icmp_table); 243 if (!net->ipv6.sysctl.icmp_hdr) 244 goto out_unregister_route_table; 245 246 err = 0; 247 out: 248 return err; 249 out_unregister_route_table: 250 unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr); 251 out_unregister_ipv6_table: 252 unregister_net_sysctl_table(net->ipv6.sysctl.hdr); 253 out_ipv6_icmp_table: 254 kfree(ipv6_icmp_table); 255 out_ipv6_route_table: 256 kfree(ipv6_route_table); 257 out_ipv6_table: 258 kfree(ipv6_table); 259 goto out; 260 } 261 262 static void __net_exit ipv6_sysctl_net_exit(struct net *net) 263 { 264 struct ctl_table *ipv6_table; 265 struct ctl_table *ipv6_route_table; 266 struct ctl_table *ipv6_icmp_table; 267 268 ipv6_table = net->ipv6.sysctl.hdr->ctl_table_arg; 269 ipv6_route_table = net->ipv6.sysctl.route_hdr->ctl_table_arg; 270 ipv6_icmp_table = net->ipv6.sysctl.icmp_hdr->ctl_table_arg; 271 272 unregister_net_sysctl_table(net->ipv6.sysctl.icmp_hdr); 273 unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr); 274 unregister_net_sysctl_table(net->ipv6.sysctl.hdr); 275 276 kfree(ipv6_table); 277 kfree(ipv6_route_table); 278 kfree(ipv6_icmp_table); 279 } 280 281 static struct pernet_operations ipv6_sysctl_net_ops = { 282 .init = ipv6_sysctl_net_init, 283 .exit = ipv6_sysctl_net_exit, 284 }; 285 286 static struct ctl_table_header *ip6_header; 287 288 int ipv6_sysctl_register(void) 289 { 290 int err = -ENOMEM; 291 292 ip6_header = register_net_sysctl(&init_net, "net/ipv6", ipv6_rotable); 293 if (!ip6_header) 294 goto out; 295 296 err = register_pernet_subsys(&ipv6_sysctl_net_ops); 297 if (err) 298 goto err_pernet; 299 out: 300 return err; 301 302 err_pernet: 303 unregister_net_sysctl_table(ip6_header); 304 goto out; 305 } 306 307 void ipv6_sysctl_unregister(void) 308 { 309 unregister_net_sysctl_table(ip6_header); 310 unregister_pernet_subsys(&ipv6_sysctl_net_ops); 311 } 312