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