proc.c 9.64 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 * INET		An implementation of the TCP/IP protocol suite for the LINUX
 *		operating system.  INET is implemented using the  BSD Socket
 *		interface as the means of communication with the user level.
 *
 *		This file implements the various access functions for the
 *		PROC file system.  It is mainly used for debugging and
 *		statistics.
 *
Linus Torvalds's avatar
Linus Torvalds committed
10
 * Version:	@(#)proc.c	1.0.5	05/27/93
11 12 13 14
 *
 * Authors:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
 *		Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
 *		Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de>
Linus Torvalds's avatar
Linus Torvalds committed
15
 *		Erik Schoenfelder, <schoenfr@ibr.cs.tu-bs.de>
16
 *
Linus Torvalds's avatar
Linus Torvalds committed
17 18 19
 * Fixes:
 *		Alan Cox	:	UDP sockets show the rxqueue/txqueue
 *					using hint flag for the netinfo.
Linus Torvalds's avatar
Linus Torvalds committed
20
 *	Pauline Middelink	:	identd support
Linus Torvalds's avatar
Linus Torvalds committed
21
 *		Alan Cox	:	Make /proc safer.
Linus Torvalds's avatar
Linus Torvalds committed
22
 *	Erik Schoenfelder	:	/proc/net/snmp
Linus Torvalds's avatar
Linus Torvalds committed
23
 *		Alan Cox	:	Handle dead sockets properly.
Linus Torvalds's avatar
Linus Torvalds committed
24
 *	Gerhard Koerting	:	Show both timers
Linus Torvalds's avatar
Linus Torvalds committed
25
 *		Alan Cox	:	Allow inode to be NULL (kernel socket)
Linus Torvalds's avatar
Linus Torvalds committed
26
 *
27 28 29 30 31 32 33 34 35 36 37 38
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 */
#include <asm/system.h>
#include <linux/autoconf.h>
#include <linux/sched.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/un.h>
#include <linux/in.h>
39
#include <linux/param.h>
Linus Torvalds's avatar
Linus Torvalds committed
40 41
#include <linux/inet.h>
#include <linux/netdevice.h>
Linus Torvalds's avatar
Linus Torvalds committed
42 43 44 45 46
#include <net/ip.h>
#include <net/icmp.h>
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/udp.h>
Linus Torvalds's avatar
Linus Torvalds committed
47
#include <linux/skbuff.h>
Linus Torvalds's avatar
Linus Torvalds committed
48 49
#include <net/sock.h>
#include <net/raw.h>
50 51 52 53 54 55 56 57

/*
 * Get__netinfo returns the length of that string.
 *
 * KNOWN BUGS
 *  As in get_unix_netinfo, the buffer might be too small. If this
 *  happens, get__netinfo returns only part of the available infos.
 */
Linus Torvalds's avatar
Linus Torvalds committed
58
static int
Linus Torvalds's avatar
Linus Torvalds committed
59
get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t offset, int length)
60
{
Linus Torvalds's avatar
Linus Torvalds committed
61 62 63 64
	struct sock **s_array;
	struct sock *sp;
	int i;
	int timer_active;
Linus Torvalds's avatar
Linus Torvalds committed
65 66 67
	int timer_active1;
	int timer_active2;
	unsigned long timer_expires;
Linus Torvalds's avatar
Linus Torvalds committed
68 69 70 71 72
	unsigned long  dest, src;
	unsigned short destp, srcp;
	int len=0;
	off_t pos=0;
	off_t begin=0;
Linus Torvalds's avatar
Linus Torvalds committed
73
  
Linus Torvalds's avatar
Linus Torvalds committed
74
	s_array = pro->sock_array;
Linus Torvalds's avatar
Linus Torvalds committed
75
	len += sprintf(buffer, "sl  local_address rem_address   st tx_queue rx_queue tr tm->when uid\n");
Linus Torvalds's avatar
Linus Torvalds committed
76
/*
Linus Torvalds's avatar
Linus Torvalds committed
77 78 79 80
 *	This was very pretty but didn't work when a socket is destroyed
 *	at the wrong moment (eg a syn recv socket getting a reset), or
 *	a memory timer destroy. Instead of playing with timers we just
 *	concede defeat and cli().
Linus Torvalds's avatar
Linus Torvalds committed
81
 */
Linus Torvalds's avatar
Linus Torvalds committed
82 83 84 85 86
	for(i = 0; i < SOCK_ARRAY_SIZE; i++) 
	{
	  	cli();
		sp = s_array[i];
		while(sp != NULL) 
Linus Torvalds's avatar
Linus Torvalds committed
87
		{
Linus Torvalds's avatar
Linus Torvalds committed
88 89 90 91 92 93 94 95
			dest  = sp->daddr;
			src   = sp->saddr;
			destp = sp->dummy_th.dest;
			srcp  = sp->dummy_th.source;

			/* Since we are Little Endian we need to swap the bytes :-( */
			destp = ntohs(destp);
			srcp  = ntohs(srcp);
Linus Torvalds's avatar
Linus Torvalds committed
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
			timer_active1 = del_timer(&sp->retransmit_timer);
			timer_active2 = del_timer(&sp->timer);
			if (!timer_active1) sp->retransmit_timer.expires=0;
			if (!timer_active2) sp->timer.expires=0;
			timer_active=0;
			timer_expires=(unsigned)-1;
			if (timer_active1 &&
			  sp->retransmit_timer.expires < timer_expires) {
			    timer_active=timer_active1;
			    timer_expires=sp->retransmit_timer.expires;
			}
			if (timer_active2 &&
			  sp->timer.expires < timer_expires) {
			    timer_active=timer_active2;
			    timer_expires=sp->timer.expires;
			}
Linus Torvalds's avatar
Linus Torvalds committed
112
			len += sprintf(buffer+len, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d %d\n",
Linus Torvalds's avatar
Linus Torvalds committed
113
				i, src, srcp, dest, destp, sp->state, 
Linus Torvalds's avatar
Linus Torvalds committed
114 115
				format==0?sp->write_seq-sp->rcv_ack_seq:sp->wmem_alloc, 
				format==0?sp->acked_seq-sp->copied_seq:sp->rmem_alloc,
Linus Torvalds's avatar
Linus Torvalds committed
116
				timer_active, timer_expires-jiffies, (unsigned) sp->retransmits,
Linus Torvalds's avatar
Linus Torvalds committed
117
				(sp->socket&&SOCK_INODE(sp->socket))?SOCK_INODE(sp->socket)->i_uid:0,
Linus Torvalds's avatar
Linus Torvalds committed
118
				timer_active?sp->timeout:0);
Linus Torvalds's avatar
Linus Torvalds committed
119 120
			if (timer_active1) add_timer(&sp->retransmit_timer);
			if (timer_active2) add_timer(&sp->timer);
Linus Torvalds's avatar
Linus Torvalds committed
121 122 123 124 125 126 127 128 129 130 131 132 133 134
			/*
			 * All sockets with (port mod SOCK_ARRAY_SIZE) = i
			 * are kept in sock_array[i], so we must follow the
			 * 'next' link to get them all.
			 */
			sp = sp->next;
			pos=begin+len;
			if(pos<offset)
			{
				len=0;
				begin=pos;
			}
			if(pos>offset+length)
				break;
Linus Torvalds's avatar
Linus Torvalds committed
135
		}
Linus Torvalds's avatar
Linus Torvalds committed
136 137 138 139
		sti();	/* We only turn interrupts back on for a moment,
			   but because the interrupt queues anything built
			   up before this will clear before we jump back
			   and cli(), so it's not as bad as it looks */
Linus Torvalds's avatar
Linus Torvalds committed
140 141
		if(pos>offset+length)
			break;
Linus Torvalds's avatar
Linus Torvalds committed
142
	}
Linus Torvalds's avatar
Linus Torvalds committed
143 144 145 146 147
	*start=buffer+(offset-begin);
	len-=(offset-begin);
	if(len>length)
	  	len=length;
	return len;
148 149 150
} 


Linus Torvalds's avatar
Linus Torvalds committed
151
int tcp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
152
{
Linus Torvalds's avatar
Linus Torvalds committed
153
	return get__netinfo(&tcp_prot, buffer,0, start, offset, length);
154 155 156
}


Linus Torvalds's avatar
Linus Torvalds committed
157
int udp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
158
{
Linus Torvalds's avatar
Linus Torvalds committed
159
	return get__netinfo(&udp_prot, buffer,1, start, offset, length);
160 161 162
}


Linus Torvalds's avatar
Linus Torvalds committed
163
int raw_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
164
{
Linus Torvalds's avatar
Linus Torvalds committed
165
	return get__netinfo(&raw_prot, buffer,1, start, offset, length);
166
}
Linus Torvalds's avatar
Linus Torvalds committed
167 168


Linus Torvalds's avatar
Linus Torvalds committed
169 170 171
/*
 *	Report socket allocation statistics [mea@utu.fi]
 */
Linus Torvalds's avatar
Linus Torvalds committed
172
int afinet_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
Linus Torvalds's avatar
Linus Torvalds committed
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
{
	/* From  net/socket.c  */
	extern int socket_get_info(char *, char **, off_t, int);
	extern struct proto packet_prot;

	int len  = socket_get_info(buffer,start,offset,length);

	len += sprintf(buffer+len,"SOCK_ARRAY_SIZE=%d\n",SOCK_ARRAY_SIZE);
	len += sprintf(buffer+len,"TCP: inuse %d highest %d\n",
		       tcp_prot.inuse, tcp_prot.highestinuse);
	len += sprintf(buffer+len,"UDP: inuse %d highest %d\n",
		       udp_prot.inuse, udp_prot.highestinuse);
	len += sprintf(buffer+len,"RAW: inuse %d highest %d\n",
		       raw_prot.inuse, raw_prot.highestinuse);
	len += sprintf(buffer+len,"PAC: inuse %d highest %d\n",
		       packet_prot.inuse, packet_prot.highestinuse);
	*start = buffer + offset;
	len -= offset;
	if (len > length)
		len = length;
	return len;
}


Linus Torvalds's avatar
Linus Torvalds committed
197 198 199 200
/* 
 *	Called from the PROCfs module. This outputs /proc/net/snmp.
 */
 
Linus Torvalds's avatar
Linus Torvalds committed
201
int snmp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
Linus Torvalds's avatar
Linus Torvalds committed
202
{
Linus Torvalds's avatar
Linus Torvalds committed
203 204 205
	extern struct tcp_mib tcp_statistics;
	extern struct udp_mib udp_statistics;
	int len;
Linus Torvalds's avatar
Linus Torvalds committed
206 207 208
/*
  extern unsigned long tcp_rx_miss, tcp_rx_hit1,tcp_rx_hit2;
*/
Linus Torvalds's avatar
Linus Torvalds committed
209

Linus Torvalds's avatar
Linus Torvalds committed
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
	len = sprintf (buffer,
		"Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates\n"
		"Ip: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
		    ip_statistics.IpForwarding, ip_statistics.IpDefaultTTL, 
		    ip_statistics.IpInReceives, ip_statistics.IpInHdrErrors, 
		    ip_statistics.IpInAddrErrors, ip_statistics.IpForwDatagrams, 
		    ip_statistics.IpInUnknownProtos, ip_statistics.IpInDiscards, 
		    ip_statistics.IpInDelivers, ip_statistics.IpOutRequests, 
		    ip_statistics.IpOutDiscards, ip_statistics.IpOutNoRoutes, 
		    ip_statistics.IpReasmTimeout, ip_statistics.IpReasmReqds, 
		    ip_statistics.IpReasmOKs, ip_statistics.IpReasmFails, 
		    ip_statistics.IpFragOKs, ip_statistics.IpFragFails, 
		    ip_statistics.IpFragCreates);
		    		
	len += sprintf (buffer + len,
		"Icmp: 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"
		"Icmp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
		    icmp_statistics.IcmpInMsgs, icmp_statistics.IcmpInErrors,
		    icmp_statistics.IcmpInDestUnreachs, icmp_statistics.IcmpInTimeExcds,
		    icmp_statistics.IcmpInParmProbs, icmp_statistics.IcmpInSrcQuenchs,
		    icmp_statistics.IcmpInRedirects, icmp_statistics.IcmpInEchos,
		    icmp_statistics.IcmpInEchoReps, icmp_statistics.IcmpInTimestamps,
		    icmp_statistics.IcmpInTimestampReps, icmp_statistics.IcmpInAddrMasks,
		    icmp_statistics.IcmpInAddrMaskReps, icmp_statistics.IcmpOutMsgs,
		    icmp_statistics.IcmpOutErrors, icmp_statistics.IcmpOutDestUnreachs,
		    icmp_statistics.IcmpOutTimeExcds, icmp_statistics.IcmpOutParmProbs,
		    icmp_statistics.IcmpOutSrcQuenchs, icmp_statistics.IcmpOutRedirects,
		    icmp_statistics.IcmpOutEchos, icmp_statistics.IcmpOutEchoReps,
		    icmp_statistics.IcmpOutTimestamps, icmp_statistics.IcmpOutTimestampReps,
		    icmp_statistics.IcmpOutAddrMasks, icmp_statistics.IcmpOutAddrMaskReps);
Linus Torvalds's avatar
Linus Torvalds committed
240
	
Linus Torvalds's avatar
Linus Torvalds committed
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
	len += sprintf (buffer + len,
		"Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs\n"
		"Tcp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
		    tcp_statistics.TcpRtoAlgorithm, tcp_statistics.TcpRtoMin,
		    tcp_statistics.TcpRtoMax, tcp_statistics.TcpMaxConn,
		    tcp_statistics.TcpActiveOpens, tcp_statistics.TcpPassiveOpens,
		    tcp_statistics.TcpAttemptFails, tcp_statistics.TcpEstabResets,
		    tcp_statistics.TcpCurrEstab, tcp_statistics.TcpInSegs,
		    tcp_statistics.TcpOutSegs, tcp_statistics.TcpRetransSegs);
		
	len += sprintf (buffer + len,
		"Udp: InDatagrams NoPorts InErrors OutDatagrams\nUdp: %lu %lu %lu %lu\n",
		    udp_statistics.UdpInDatagrams, udp_statistics.UdpNoPorts,
		    udp_statistics.UdpInErrors, udp_statistics.UdpOutDatagrams);	    
/*	
Linus Torvalds's avatar
Linus Torvalds committed
256 257 258 259
	  len += sprintf( buffer + len,
	  	"TCP fast path RX:  H2: %ul H1: %ul L: %ul\n",
	  		tcp_rx_hit2,tcp_rx_hit1,tcp_rx_miss);
*/
Linus Torvalds's avatar
Linus Torvalds committed
260
	
Linus Torvalds's avatar
Linus Torvalds committed
261 262 263 264 265 266 267 268 269 270
	if (offset >= len)
	{
		*start = buffer;
		return 0;
	}
	*start = buffer + offset;
	len -= offset;
	if (len > length)
		len = length;
	return len;
Linus Torvalds's avatar
Linus Torvalds committed
271
}