162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * INET An implementation of the TCP/IP protocol suite for the LINUX 462306a36Sopenharmony_ci * operating system. INET is implemented using the BSD Socket 562306a36Sopenharmony_ci * interface as the means of communication with the user level. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This file implements the various access functions for the 862306a36Sopenharmony_ci * PROC file system. This is very similar to the IPv4 version, 962306a36Sopenharmony_ci * except it reports the sockets in the INET6 address family. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Authors: David S. Miller (davem@caip.rutgers.edu) 1262306a36Sopenharmony_ci * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci#include <linux/socket.h> 1562306a36Sopenharmony_ci#include <linux/net.h> 1662306a36Sopenharmony_ci#include <linux/ipv6.h> 1762306a36Sopenharmony_ci#include <linux/proc_fs.h> 1862306a36Sopenharmony_ci#include <linux/seq_file.h> 1962306a36Sopenharmony_ci#include <linux/stddef.h> 2062306a36Sopenharmony_ci#include <linux/export.h> 2162306a36Sopenharmony_ci#include <net/net_namespace.h> 2262306a36Sopenharmony_ci#include <net/ip.h> 2362306a36Sopenharmony_ci#include <net/sock.h> 2462306a36Sopenharmony_ci#include <net/tcp.h> 2562306a36Sopenharmony_ci#include <net/udp.h> 2662306a36Sopenharmony_ci#include <net/transp_v6.h> 2762306a36Sopenharmony_ci#include <net/ipv6.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define MAX4(a, b, c, d) \ 3062306a36Sopenharmony_ci max_t(u32, max_t(u32, a, b), max_t(u32, c, d)) 3162306a36Sopenharmony_ci#define SNMP_MIB_MAX MAX4(UDP_MIB_MAX, TCP_MIB_MAX, \ 3262306a36Sopenharmony_ci IPSTATS_MIB_MAX, ICMP_MIB_MAX) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int sockstat6_seq_show(struct seq_file *seq, void *v) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct net *net = seq->private; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci seq_printf(seq, "TCP6: inuse %d\n", 3962306a36Sopenharmony_ci sock_prot_inuse_get(net, &tcpv6_prot)); 4062306a36Sopenharmony_ci seq_printf(seq, "UDP6: inuse %d\n", 4162306a36Sopenharmony_ci sock_prot_inuse_get(net, &udpv6_prot)); 4262306a36Sopenharmony_ci seq_printf(seq, "UDPLITE6: inuse %d\n", 4362306a36Sopenharmony_ci sock_prot_inuse_get(net, &udplitev6_prot)); 4462306a36Sopenharmony_ci seq_printf(seq, "RAW6: inuse %d\n", 4562306a36Sopenharmony_ci sock_prot_inuse_get(net, &rawv6_prot)); 4662306a36Sopenharmony_ci seq_printf(seq, "FRAG6: inuse %u memory %lu\n", 4762306a36Sopenharmony_ci atomic_read(&net->ipv6.fqdir->rhashtable.nelems), 4862306a36Sopenharmony_ci frag_mem_limit(net->ipv6.fqdir)); 4962306a36Sopenharmony_ci return 0; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic const struct snmp_mib snmp6_ipstats_list[] = { 5362306a36Sopenharmony_ci/* ipv6 mib according to RFC 2465 */ 5462306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INPKTS), 5562306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InHdrErrors", IPSTATS_MIB_INHDRERRORS), 5662306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InTooBigErrors", IPSTATS_MIB_INTOOBIGERRORS), 5762306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InNoRoutes", IPSTATS_MIB_INNOROUTES), 5862306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InAddrErrors", IPSTATS_MIB_INADDRERRORS), 5962306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InUnknownProtos", IPSTATS_MIB_INUNKNOWNPROTOS), 6062306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InTruncatedPkts", IPSTATS_MIB_INTRUNCATEDPKTS), 6162306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InDiscards", IPSTATS_MIB_INDISCARDS), 6262306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InDelivers", IPSTATS_MIB_INDELIVERS), 6362306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6OutForwDatagrams", IPSTATS_MIB_OUTFORWDATAGRAMS), 6462306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6OutRequests", IPSTATS_MIB_OUTPKTS), 6562306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6OutDiscards", IPSTATS_MIB_OUTDISCARDS), 6662306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6OutNoRoutes", IPSTATS_MIB_OUTNOROUTES), 6762306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6ReasmTimeout", IPSTATS_MIB_REASMTIMEOUT), 6862306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6ReasmReqds", IPSTATS_MIB_REASMREQDS), 6962306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6ReasmOKs", IPSTATS_MIB_REASMOKS), 7062306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6ReasmFails", IPSTATS_MIB_REASMFAILS), 7162306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6FragOKs", IPSTATS_MIB_FRAGOKS), 7262306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6FragFails", IPSTATS_MIB_FRAGFAILS), 7362306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6FragCreates", IPSTATS_MIB_FRAGCREATES), 7462306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InMcastPkts", IPSTATS_MIB_INMCASTPKTS), 7562306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6OutMcastPkts", IPSTATS_MIB_OUTMCASTPKTS), 7662306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InOctets", IPSTATS_MIB_INOCTETS), 7762306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6OutOctets", IPSTATS_MIB_OUTOCTETS), 7862306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InMcastOctets", IPSTATS_MIB_INMCASTOCTETS), 7962306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6OutMcastOctets", IPSTATS_MIB_OUTMCASTOCTETS), 8062306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InBcastOctets", IPSTATS_MIB_INBCASTOCTETS), 8162306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6OutBcastOctets", IPSTATS_MIB_OUTBCASTOCTETS), 8262306a36Sopenharmony_ci /* IPSTATS_MIB_CSUMERRORS is not relevant in IPv6 (no checksum) */ 8362306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InNoECTPkts", IPSTATS_MIB_NOECTPKTS), 8462306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InECT1Pkts", IPSTATS_MIB_ECT1PKTS), 8562306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InECT0Pkts", IPSTATS_MIB_ECT0PKTS), 8662306a36Sopenharmony_ci SNMP_MIB_ITEM("Ip6InCEPkts", IPSTATS_MIB_CEPKTS), 8762306a36Sopenharmony_ci SNMP_MIB_SENTINEL 8862306a36Sopenharmony_ci}; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic const struct snmp_mib snmp6_icmp6_list[] = { 9162306a36Sopenharmony_ci/* icmpv6 mib according to RFC 2466 */ 9262306a36Sopenharmony_ci SNMP_MIB_ITEM("Icmp6InMsgs", ICMP6_MIB_INMSGS), 9362306a36Sopenharmony_ci SNMP_MIB_ITEM("Icmp6InErrors", ICMP6_MIB_INERRORS), 9462306a36Sopenharmony_ci SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS), 9562306a36Sopenharmony_ci SNMP_MIB_ITEM("Icmp6OutErrors", ICMP6_MIB_OUTERRORS), 9662306a36Sopenharmony_ci SNMP_MIB_ITEM("Icmp6InCsumErrors", ICMP6_MIB_CSUMERRORS), 9762306a36Sopenharmony_ci SNMP_MIB_ITEM("Icmp6OutRateLimitHost", ICMP6_MIB_RATELIMITHOST), 9862306a36Sopenharmony_ci SNMP_MIB_SENTINEL 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* RFC 4293 v6 ICMPMsgStatsTable; named items for RFC 2466 compatibility */ 10262306a36Sopenharmony_cistatic const char *const icmp6type2name[256] = { 10362306a36Sopenharmony_ci [ICMPV6_DEST_UNREACH] = "DestUnreachs", 10462306a36Sopenharmony_ci [ICMPV6_PKT_TOOBIG] = "PktTooBigs", 10562306a36Sopenharmony_ci [ICMPV6_TIME_EXCEED] = "TimeExcds", 10662306a36Sopenharmony_ci [ICMPV6_PARAMPROB] = "ParmProblems", 10762306a36Sopenharmony_ci [ICMPV6_ECHO_REQUEST] = "Echos", 10862306a36Sopenharmony_ci [ICMPV6_ECHO_REPLY] = "EchoReplies", 10962306a36Sopenharmony_ci [ICMPV6_MGM_QUERY] = "GroupMembQueries", 11062306a36Sopenharmony_ci [ICMPV6_MGM_REPORT] = "GroupMembResponses", 11162306a36Sopenharmony_ci [ICMPV6_MGM_REDUCTION] = "GroupMembReductions", 11262306a36Sopenharmony_ci [ICMPV6_MLD2_REPORT] = "MLDv2Reports", 11362306a36Sopenharmony_ci [NDISC_ROUTER_ADVERTISEMENT] = "RouterAdvertisements", 11462306a36Sopenharmony_ci [NDISC_ROUTER_SOLICITATION] = "RouterSolicits", 11562306a36Sopenharmony_ci [NDISC_NEIGHBOUR_ADVERTISEMENT] = "NeighborAdvertisements", 11662306a36Sopenharmony_ci [NDISC_NEIGHBOUR_SOLICITATION] = "NeighborSolicits", 11762306a36Sopenharmony_ci [NDISC_REDIRECT] = "Redirects", 11862306a36Sopenharmony_ci}; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic const struct snmp_mib snmp6_udp6_list[] = { 12262306a36Sopenharmony_ci SNMP_MIB_ITEM("Udp6InDatagrams", UDP_MIB_INDATAGRAMS), 12362306a36Sopenharmony_ci SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS), 12462306a36Sopenharmony_ci SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS), 12562306a36Sopenharmony_ci SNMP_MIB_ITEM("Udp6OutDatagrams", UDP_MIB_OUTDATAGRAMS), 12662306a36Sopenharmony_ci SNMP_MIB_ITEM("Udp6RcvbufErrors", UDP_MIB_RCVBUFERRORS), 12762306a36Sopenharmony_ci SNMP_MIB_ITEM("Udp6SndbufErrors", UDP_MIB_SNDBUFERRORS), 12862306a36Sopenharmony_ci SNMP_MIB_ITEM("Udp6InCsumErrors", UDP_MIB_CSUMERRORS), 12962306a36Sopenharmony_ci SNMP_MIB_ITEM("Udp6IgnoredMulti", UDP_MIB_IGNOREDMULTI), 13062306a36Sopenharmony_ci SNMP_MIB_ITEM("Udp6MemErrors", UDP_MIB_MEMERRORS), 13162306a36Sopenharmony_ci SNMP_MIB_SENTINEL 13262306a36Sopenharmony_ci}; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic const struct snmp_mib snmp6_udplite6_list[] = { 13562306a36Sopenharmony_ci SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS), 13662306a36Sopenharmony_ci SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), 13762306a36Sopenharmony_ci SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), 13862306a36Sopenharmony_ci SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), 13962306a36Sopenharmony_ci SNMP_MIB_ITEM("UdpLite6RcvbufErrors", UDP_MIB_RCVBUFERRORS), 14062306a36Sopenharmony_ci SNMP_MIB_ITEM("UdpLite6SndbufErrors", UDP_MIB_SNDBUFERRORS), 14162306a36Sopenharmony_ci SNMP_MIB_ITEM("UdpLite6InCsumErrors", UDP_MIB_CSUMERRORS), 14262306a36Sopenharmony_ci SNMP_MIB_ITEM("UdpLite6MemErrors", UDP_MIB_MEMERRORS), 14362306a36Sopenharmony_ci SNMP_MIB_SENTINEL 14462306a36Sopenharmony_ci}; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic void snmp6_seq_show_icmpv6msg(struct seq_file *seq, atomic_long_t *smib) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci char name[32]; 14962306a36Sopenharmony_ci int i; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* print by name -- deprecated items */ 15262306a36Sopenharmony_ci for (i = 0; i < ICMP6MSG_MIB_MAX; i++) { 15362306a36Sopenharmony_ci int icmptype; 15462306a36Sopenharmony_ci const char *p; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci icmptype = i & 0xff; 15762306a36Sopenharmony_ci p = icmp6type2name[icmptype]; 15862306a36Sopenharmony_ci if (!p) /* don't print un-named types here */ 15962306a36Sopenharmony_ci continue; 16062306a36Sopenharmony_ci snprintf(name, sizeof(name), "Icmp6%s%s", 16162306a36Sopenharmony_ci i & 0x100 ? "Out" : "In", p); 16262306a36Sopenharmony_ci seq_printf(seq, "%-32s\t%lu\n", name, 16362306a36Sopenharmony_ci atomic_long_read(smib + i)); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* print by number (nonzero only) - ICMPMsgStat format */ 16762306a36Sopenharmony_ci for (i = 0; i < ICMP6MSG_MIB_MAX; i++) { 16862306a36Sopenharmony_ci unsigned long val; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci val = atomic_long_read(smib + i); 17162306a36Sopenharmony_ci if (!val) 17262306a36Sopenharmony_ci continue; 17362306a36Sopenharmony_ci snprintf(name, sizeof(name), "Icmp6%sType%u", 17462306a36Sopenharmony_ci i & 0x100 ? "Out" : "In", i & 0xff); 17562306a36Sopenharmony_ci seq_printf(seq, "%-32s\t%lu\n", name, val); 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* can be called either with percpu mib (pcpumib != NULL), 18062306a36Sopenharmony_ci * or shared one (smib != NULL) 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_cistatic void snmp6_seq_show_item(struct seq_file *seq, void __percpu *pcpumib, 18362306a36Sopenharmony_ci atomic_long_t *smib, 18462306a36Sopenharmony_ci const struct snmp_mib *itemlist) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci unsigned long buff[SNMP_MIB_MAX]; 18762306a36Sopenharmony_ci int i; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (pcpumib) { 19062306a36Sopenharmony_ci memset(buff, 0, sizeof(unsigned long) * SNMP_MIB_MAX); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci snmp_get_cpu_field_batch(buff, itemlist, pcpumib); 19362306a36Sopenharmony_ci for (i = 0; itemlist[i].name; i++) 19462306a36Sopenharmony_ci seq_printf(seq, "%-32s\t%lu\n", 19562306a36Sopenharmony_ci itemlist[i].name, buff[i]); 19662306a36Sopenharmony_ci } else { 19762306a36Sopenharmony_ci for (i = 0; itemlist[i].name; i++) 19862306a36Sopenharmony_ci seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name, 19962306a36Sopenharmony_ci atomic_long_read(smib + itemlist[i].entry)); 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic void snmp6_seq_show_item64(struct seq_file *seq, void __percpu *mib, 20462306a36Sopenharmony_ci const struct snmp_mib *itemlist, size_t syncpoff) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci u64 buff64[SNMP_MIB_MAX]; 20762306a36Sopenharmony_ci int i; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci memset(buff64, 0, sizeof(u64) * SNMP_MIB_MAX); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci snmp_get_cpu_field64_batch(buff64, itemlist, mib, syncpoff); 21262306a36Sopenharmony_ci for (i = 0; itemlist[i].name; i++) 21362306a36Sopenharmony_ci seq_printf(seq, "%-32s\t%llu\n", itemlist[i].name, buff64[i]); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic int snmp6_seq_show(struct seq_file *seq, void *v) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci struct net *net = (struct net *)seq->private; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci snmp6_seq_show_item64(seq, net->mib.ipv6_statistics, 22162306a36Sopenharmony_ci snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp)); 22262306a36Sopenharmony_ci snmp6_seq_show_item(seq, net->mib.icmpv6_statistics, 22362306a36Sopenharmony_ci NULL, snmp6_icmp6_list); 22462306a36Sopenharmony_ci snmp6_seq_show_icmpv6msg(seq, net->mib.icmpv6msg_statistics->mibs); 22562306a36Sopenharmony_ci snmp6_seq_show_item(seq, net->mib.udp_stats_in6, 22662306a36Sopenharmony_ci NULL, snmp6_udp6_list); 22762306a36Sopenharmony_ci snmp6_seq_show_item(seq, net->mib.udplite_stats_in6, 22862306a36Sopenharmony_ci NULL, snmp6_udplite6_list); 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic int snmp6_dev_seq_show(struct seq_file *seq, void *v) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct inet6_dev *idev = (struct inet6_dev *)seq->private; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); 23762306a36Sopenharmony_ci snmp6_seq_show_item64(seq, idev->stats.ipv6, 23862306a36Sopenharmony_ci snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp)); 23962306a36Sopenharmony_ci snmp6_seq_show_item(seq, NULL, idev->stats.icmpv6dev->mibs, 24062306a36Sopenharmony_ci snmp6_icmp6_list); 24162306a36Sopenharmony_ci snmp6_seq_show_icmpv6msg(seq, idev->stats.icmpv6msgdev->mibs); 24262306a36Sopenharmony_ci return 0; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ciint snmp6_register_dev(struct inet6_dev *idev) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci struct proc_dir_entry *p; 24862306a36Sopenharmony_ci struct net *net; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (!idev || !idev->dev) 25162306a36Sopenharmony_ci return -EINVAL; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci net = dev_net(idev->dev); 25462306a36Sopenharmony_ci if (!net->mib.proc_net_devsnmp6) 25562306a36Sopenharmony_ci return -ENOENT; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci p = proc_create_single_data(idev->dev->name, 0444, 25862306a36Sopenharmony_ci net->mib.proc_net_devsnmp6, snmp6_dev_seq_show, idev); 25962306a36Sopenharmony_ci if (!p) 26062306a36Sopenharmony_ci return -ENOMEM; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci idev->stats.proc_dir_entry = p; 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ciint snmp6_unregister_dev(struct inet6_dev *idev) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct net *net = dev_net(idev->dev); 26962306a36Sopenharmony_ci if (!net->mib.proc_net_devsnmp6) 27062306a36Sopenharmony_ci return -ENOENT; 27162306a36Sopenharmony_ci if (!idev->stats.proc_dir_entry) 27262306a36Sopenharmony_ci return -EINVAL; 27362306a36Sopenharmony_ci proc_remove(idev->stats.proc_dir_entry); 27462306a36Sopenharmony_ci idev->stats.proc_dir_entry = NULL; 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic int __net_init ipv6_proc_init_net(struct net *net) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci if (!proc_create_net_single("sockstat6", 0444, net->proc_net, 28162306a36Sopenharmony_ci sockstat6_seq_show, NULL)) 28262306a36Sopenharmony_ci return -ENOMEM; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (!proc_create_net_single("snmp6", 0444, net->proc_net, 28562306a36Sopenharmony_ci snmp6_seq_show, NULL)) 28662306a36Sopenharmony_ci goto proc_snmp6_fail; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci net->mib.proc_net_devsnmp6 = proc_mkdir("dev_snmp6", net->proc_net); 28962306a36Sopenharmony_ci if (!net->mib.proc_net_devsnmp6) 29062306a36Sopenharmony_ci goto proc_dev_snmp6_fail; 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ciproc_dev_snmp6_fail: 29462306a36Sopenharmony_ci remove_proc_entry("snmp6", net->proc_net); 29562306a36Sopenharmony_ciproc_snmp6_fail: 29662306a36Sopenharmony_ci remove_proc_entry("sockstat6", net->proc_net); 29762306a36Sopenharmony_ci return -ENOMEM; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic void __net_exit ipv6_proc_exit_net(struct net *net) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci remove_proc_entry("sockstat6", net->proc_net); 30362306a36Sopenharmony_ci remove_proc_entry("dev_snmp6", net->proc_net); 30462306a36Sopenharmony_ci remove_proc_entry("snmp6", net->proc_net); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic struct pernet_operations ipv6_proc_ops = { 30862306a36Sopenharmony_ci .init = ipv6_proc_init_net, 30962306a36Sopenharmony_ci .exit = ipv6_proc_exit_net, 31062306a36Sopenharmony_ci}; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ciint __init ipv6_misc_proc_init(void) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci return register_pernet_subsys(&ipv6_proc_ops); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_civoid ipv6_misc_proc_exit(void) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci unregister_pernet_subsys(&ipv6_proc_ops); 32062306a36Sopenharmony_ci} 321