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