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