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