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