1 /*
2  * INET		An implementation of the TCP/IP protocol suite for the LINUX
3  *		operating system.  INET is implemented using the  BSD Socket
4  *		interface as the means of communication with the user level.
5  *
6  *		This file implements the various access functions for the
7  *		PROC file system.  It is mainly used for debugging and
8  *		statistics.
9  *
10  * Version:	$Id: proc.c,v 1.45 2001/05/16 16:45:35 davem Exp $
11  *
12  * Authors:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
13  *		Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
14  *		Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de>
15  *		Erik Schoenfelder, <schoenfr@ibr.cs.tu-bs.de>
16  *
17  * Fixes:
18  *		Alan Cox	:	UDP sockets show the rxqueue/txqueue
19  *					using hint flag for the netinfo.
20  *	Pauline Middelink	:	identd support
21  *		Alan Cox	:	Make /proc safer.
22  *	Erik Schoenfelder	:	/proc/net/snmp
23  *		Alan Cox	:	Handle dead sockets properly.
24  *	Gerhard Koerting	:	Show both timers
25  *		Alan Cox	:	Allow inode to be NULL (kernel socket)
26  *	Andi Kleen		:	Add support for open_requests and
27  *					split functions for more readibility.
28  *	Andi Kleen		:	Add support for /proc/net/netstat
29  *
30  *		This program is free software; you can redistribute it and/or
31  *		modify it under the terms of the GNU General Public License
32  *		as published by the Free Software Foundation; either version
33  *		2 of the License, or (at your option) any later version.
34  */
35 #include <asm/system.h>
36 #include <linux/sched.h>
37 #include <linux/socket.h>
38 #include <linux/net.h>
39 #include <linux/un.h>
40 #include <linux/in.h>
41 #include <linux/param.h>
42 #include <linux/inet.h>
43 #include <linux/netdevice.h>
44 #include <net/ip.h>
45 #include <net/icmp.h>
46 #include <net/protocol.h>
47 #include <net/tcp.h>
48 #include <net/udp.h>
49 #include <linux/skbuff.h>
50 #include <net/sock.h>
51 #include <net/raw.h>
52 
fold_prot_inuse(struct proto * proto)53 static int fold_prot_inuse(struct proto *proto)
54 {
55 	int res = 0;
56 	int cpu;
57 
58 	for (cpu=0; cpu<smp_num_cpus; cpu++)
59 		res += proto->stats[cpu_logical_map(cpu)].inuse;
60 
61 	return res;
62 }
63 
64 /*
65  *	Report socket allocation statistics [mea@utu.fi]
66  */
afinet_get_info(char * buffer,char ** start,off_t offset,int length)67 int afinet_get_info(char *buffer, char **start, off_t offset, int length)
68 {
69 	/* From  net/socket.c  */
70 	extern int socket_get_info(char *, char **, off_t, int);
71 
72 	int len  = socket_get_info(buffer,start,offset,length);
73 
74 	len += sprintf(buffer+len,"TCP: inuse %d orphan %d tw %d alloc %d mem %d\n",
75 		       fold_prot_inuse(&tcp_prot),
76 		       atomic_read(&tcp_orphan_count), tcp_tw_count,
77 		       atomic_read(&tcp_sockets_allocated),
78 		       atomic_read(&tcp_memory_allocated));
79 	len += sprintf(buffer+len,"UDP: inuse %d\n",
80 		       fold_prot_inuse(&udp_prot));
81 	len += sprintf(buffer+len,"RAW: inuse %d\n",
82 		       fold_prot_inuse(&raw_prot));
83 	len += sprintf(buffer+len, "FRAG: inuse %d memory %d\n",
84 		       ip_frag_nqueues, atomic_read(&ip_frag_mem));
85 	if (offset >= len)
86 	{
87 		*start = buffer;
88 		return 0;
89 	}
90 	*start = buffer + offset;
91 	len -= offset;
92 	if (len > length)
93 		len = length;
94 	if (len < 0)
95 		len = 0;
96 	return len;
97 }
98 
fold_field(unsigned long * begin,int sz,int nr)99 static unsigned long fold_field(unsigned long *begin, int sz, int nr)
100 {
101 	unsigned long res = 0;
102 	int i;
103 
104 	sz /= sizeof(unsigned long);
105 
106 	for (i=0; i<smp_num_cpus; i++) {
107 		res += begin[2*cpu_logical_map(i)*sz + nr];
108 		res += begin[(2*cpu_logical_map(i)+1)*sz + nr];
109 	}
110 	return res;
111 }
112 
113 /*
114  *	Called from the PROCfs module. This outputs /proc/net/snmp.
115  */
116 
snmp_get_info(char * buffer,char ** start,off_t offset,int length)117 int snmp_get_info(char *buffer, char **start, off_t offset, int length)
118 {
119 	extern int sysctl_ip_default_ttl;
120 	int len, i;
121 
122 	len = sprintf (buffer,
123 		"Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates\n"
124 		"Ip: %d %d", ipv4_devconf.forwarding ? 1 : 2, sysctl_ip_default_ttl);
125 	for (i=0; i<offsetof(struct ip_mib, __pad)/sizeof(unsigned long); i++)
126 		len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)ip_statistics, sizeof(struct ip_mib), i));
127 
128 	len += sprintf (buffer + len,
129 		"\nIcmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps\n"
130 		  "Icmp:");
131 	for (i=0; i<offsetof(struct icmp_mib, dummy)/sizeof(unsigned long); i++)
132 		len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)icmp_statistics, sizeof(struct icmp_mib), i));
133 
134 	len += sprintf (buffer + len,
135 		"\nTcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts\n"
136 		  "Tcp:");
137 	for (i=0; i<offsetof(struct tcp_mib, __pad)/sizeof(unsigned long); i++) {
138 		if (i == (offsetof(struct tcp_mib, TcpMaxConn) / sizeof(unsigned long)))
139 			/* MaxConn field is negative, RFC 2012 */
140 			len += sprintf(buffer+len, " %ld",
141 				       fold_field((unsigned long*)tcp_statistics,
142 					          sizeof(struct tcp_mib), i));
143 		else
144 			len += sprintf(buffer+len, " %lu",
145 				       fold_field((unsigned long*)tcp_statistics,
146 					          sizeof(struct tcp_mib), i));
147 	}
148 	len += sprintf (buffer + len,
149 		"\nUdp: InDatagrams NoPorts InErrors OutDatagrams\n"
150 		  "Udp:");
151 	for (i=0; i<offsetof(struct udp_mib, __pad)/sizeof(unsigned long); i++)
152 		len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)udp_statistics, sizeof(struct udp_mib), i));
153 
154 	len += sprintf (buffer + len, "\n");
155 
156 	if (offset >= len)
157 	{
158 		*start = buffer;
159 		return 0;
160 	}
161 	*start = buffer + offset;
162 	len -= offset;
163 	if (len > length)
164 		len = length;
165 	if (len < 0)
166 		len = 0;
167 	return len;
168 }
169 
170 /*
171  *	Output /proc/net/netstat
172  */
173 
netstat_get_info(char * buffer,char ** start,off_t offset,int length)174 int netstat_get_info(char *buffer, char **start, off_t offset, int length)
175 {
176 	int len, i;
177 
178 	len = sprintf(buffer,
179 		      "TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
180 		      " EmbryonicRsts PruneCalled RcvPruned OfoPruned"
181 		      " OutOfWindowIcmps LockDroppedIcmps ArpFilter"
182 		      " TW TWRecycled TWKilled"
183 		      " PAWSPassive PAWSActive PAWSEstab"
184 		      " DelayedACKs DelayedACKLocked DelayedACKLost"
185 		      " ListenOverflows ListenDrops"
186 		      " TCPPrequeued TCPDirectCopyFromBacklog"
187 		      " TCPDirectCopyFromPrequeue TCPPrequeueDropped"
188 		      " TCPHPHits TCPHPHitsToUser"
189 		      " TCPPureAcks TCPHPAcks"
190 		      " TCPRenoRecovery TCPSackRecovery"
191 		      " TCPSACKReneging"
192 		      " TCPFACKReorder TCPSACKReorder TCPRenoReorder TCPTSReorder"
193 		      " TCPFullUndo TCPPartialUndo TCPDSACKUndo TCPLossUndo"
194 		      " TCPLoss TCPLostRetransmit"
195 		      " TCPRenoFailures TCPSackFailures TCPLossFailures"
196 		      " TCPFastRetrans TCPForwardRetrans TCPSlowStartRetrans"
197 		      " TCPTimeouts"
198 		      " TCPRenoRecoveryFail TCPSackRecoveryFail"
199 		      " TCPSchedulerFailed TCPRcvCollapsed"
200 		      " TCPDSACKOldSent TCPDSACKOfoSent TCPDSACKRecv TCPDSACKOfoRecv"
201 		      " TCPAbortOnSyn TCPAbortOnData TCPAbortOnClose"
202 		      " TCPAbortOnMemory TCPAbortOnTimeout TCPAbortOnLinger"
203 		      " TCPAbortFailed TCPMemoryPressures\n"
204 		      "TcpExt:");
205 	for (i=0; i<offsetof(struct linux_mib, __pad)/sizeof(unsigned long); i++)
206 		len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)net_statistics, sizeof(struct linux_mib), i));
207 
208 	len += sprintf (buffer + len, "\n");
209 
210 	if (offset >= len)
211 	{
212 		*start = buffer;
213 		return 0;
214 	}
215 	*start = buffer + offset;
216 	len -= offset;
217 	if (len > length)
218 		len = length;
219 	if (len < 0)
220 		len = 0;
221 	return len;
222 }
223