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