1 /* 2 * sysctl_net_ipv6.c: sysctl interface to net IPV6 subsystem. 3 * 4 * Changes: 5 * YOSHIFUJI Hideaki @USAGI: added icmp sysctl table. 6 */ 7 8 #include <linux/mm.h> 9 #include <linux/sysctl.h> 10 #include <linux/in6.h> 11 #include <linux/ipv6.h> 12 #include <linux/slab.h> 13 #include <linux/export.h> 14 #include <net/ndisc.h> 15 #include <net/ipv6.h> 16 #include <net/addrconf.h> 17 #include <net/inet_frag.h> 18 19 static struct ctl_table empty[1]; 20 21 static ctl_table ipv6_static_skeleton[] = { 22 { 23 .procname = "neigh", 24 .maxlen = 0, 25 .mode = 0555, 26 .child = empty, 27 }, 28 { } 29 }; 30 31 static ctl_table ipv6_table_template[] = { 32 { 33 .procname = "route", 34 .maxlen = 0, 35 .mode = 0555, 36 .child = ipv6_route_table_template 37 }, 38 { 39 .procname = "icmp", 40 .maxlen = 0, 41 .mode = 0555, 42 .child = ipv6_icmp_table_template 43 }, 44 { 45 .procname = "bindv6only", 46 .data = &init_net.ipv6.sysctl.bindv6only, 47 .maxlen = sizeof(int), 48 .mode = 0644, 49 .proc_handler = proc_dointvec 50 }, 51 { } 52 }; 53 54 static ctl_table ipv6_rotable[] = { 55 { 56 .procname = "mld_max_msf", 57 .data = &sysctl_mld_max_msf, 58 .maxlen = sizeof(int), 59 .mode = 0644, 60 .proc_handler = proc_dointvec 61 }, 62 { } 63 }; 64 65 struct ctl_path net_ipv6_ctl_path[] = { 66 { .procname = "net", }, 67 { .procname = "ipv6", }, 68 { }, 69 }; 70 EXPORT_SYMBOL_GPL(net_ipv6_ctl_path); 71 72 static int __net_init ipv6_sysctl_net_init(struct net *net) 73 { 74 struct ctl_table *ipv6_table; 75 struct ctl_table *ipv6_route_table; 76 struct ctl_table *ipv6_icmp_table; 77 int err; 78 79 err = -ENOMEM; 80 ipv6_table = kmemdup(ipv6_table_template, sizeof(ipv6_table_template), 81 GFP_KERNEL); 82 if (!ipv6_table) 83 goto out; 84 85 ipv6_route_table = ipv6_route_sysctl_init(net); 86 if (!ipv6_route_table) 87 goto out_ipv6_table; 88 ipv6_table[0].child = ipv6_route_table; 89 90 ipv6_icmp_table = ipv6_icmp_sysctl_init(net); 91 if (!ipv6_icmp_table) 92 goto out_ipv6_route_table; 93 ipv6_table[1].child = ipv6_icmp_table; 94 95 ipv6_table[2].data = &net->ipv6.sysctl.bindv6only; 96 97 net->ipv6.sysctl.table = register_net_sysctl_table(net, net_ipv6_ctl_path, 98 ipv6_table); 99 if (!net->ipv6.sysctl.table) 100 goto out_ipv6_icmp_table; 101 102 err = 0; 103 out: 104 return err; 105 106 out_ipv6_icmp_table: 107 kfree(ipv6_icmp_table); 108 out_ipv6_route_table: 109 kfree(ipv6_route_table); 110 out_ipv6_table: 111 kfree(ipv6_table); 112 goto out; 113 } 114 115 static void __net_exit ipv6_sysctl_net_exit(struct net *net) 116 { 117 struct ctl_table *ipv6_table; 118 struct ctl_table *ipv6_route_table; 119 struct ctl_table *ipv6_icmp_table; 120 121 ipv6_table = net->ipv6.sysctl.table->ctl_table_arg; 122 ipv6_route_table = ipv6_table[0].child; 123 ipv6_icmp_table = ipv6_table[1].child; 124 125 unregister_net_sysctl_table(net->ipv6.sysctl.table); 126 127 kfree(ipv6_table); 128 kfree(ipv6_route_table); 129 kfree(ipv6_icmp_table); 130 } 131 132 static struct pernet_operations ipv6_sysctl_net_ops = { 133 .init = ipv6_sysctl_net_init, 134 .exit = ipv6_sysctl_net_exit, 135 }; 136 137 static struct ctl_table_header *ip6_header; 138 139 int ipv6_sysctl_register(void) 140 { 141 int err = -ENOMEM; 142 143 ip6_header = register_net_sysctl_rotable(net_ipv6_ctl_path, ipv6_rotable); 144 if (ip6_header == NULL) 145 goto out; 146 147 err = register_pernet_subsys(&ipv6_sysctl_net_ops); 148 if (err) 149 goto err_pernet; 150 out: 151 return err; 152 153 err_pernet: 154 unregister_net_sysctl_table(ip6_header); 155 goto out; 156 } 157 158 void ipv6_sysctl_unregister(void) 159 { 160 unregister_net_sysctl_table(ip6_header); 161 unregister_pernet_subsys(&ipv6_sysctl_net_ops); 162 } 163 164 static struct ctl_table_header *ip6_base; 165 166 int ipv6_static_sysctl_register(void) 167 { 168 ip6_base = register_sysctl_paths(net_ipv6_ctl_path, ipv6_static_skeleton); 169 if (ip6_base == NULL) 170 return -ENOMEM; 171 return 0; 172 } 173 174 void ipv6_static_sysctl_unregister(void) 175 { 176 unregister_net_sysctl_table(ip6_base); 177 } 178