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