pre-2.3.4..
[davej-history.git] / net / ipv4 / proc.c
blob4c05059f8ea4f11f01966b991c21557f723f7738
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.
6 * This file implements the various access functions for the
7 * PROC file system. It is mainly used for debugging and
8 * statistics.
10 * Version: $Id: proc.c,v 1.34 1999/02/08 11:20:34 davem Exp $
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>
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
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.
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>
53 /* Format a single open_request into tmpbuf. */
54 static inline void get__openreq(struct sock *sk, struct open_request *req,
55 char *tmpbuf,
56 int i)
58 sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
59 " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u",
61 (long unsigned int)req->af.v4_req.loc_addr,
62 ntohs(sk->sport),
63 (long unsigned int)req->af.v4_req.rmt_addr,
64 ntohs(req->rmt_port),
65 TCP_SYN_RECV,
66 0,0, /* could print option size, but that is af dependent. */
67 1, /* timers active (only the expire timer) */
68 (unsigned long)(req->expires - jiffies),
69 req->retrans,
70 sk->socket ? sk->socket->inode->i_uid : 0,
71 0, /* non standard timer */
72 0 /* open_requests have no inode */
73 );
76 /* Format a single socket into tmpbuf. */
77 static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format)
79 unsigned long dest, src;
80 unsigned short destp, srcp;
81 int timer_active, timer_active1, timer_active2;
82 int tw_bucket = 0;
83 unsigned long timer_expires;
84 struct tcp_opt *tp = &sp->tp_pinfo.af_tcp;
86 dest = sp->daddr;
87 src = sp->rcv_saddr;
88 destp = sp->dport;
89 srcp = sp->sport;
91 /* FIXME: The fact that retransmit_timer occurs as a field
92 * in two different parts of the socket structure is,
93 * to say the least, confusing. This code now uses the
94 * right retransmit_timer variable, but I'm not sure
95 * the rest of the timer stuff is still correct.
96 * In particular I'm not sure what the timeout value
97 * is suppose to reflect (as opposed to tm->when). -- erics
100 destp = ntohs(destp);
101 srcp = ntohs(srcp);
102 if((format == 0) && (sp->state == TCP_TIME_WAIT)) {
103 extern int tcp_tw_death_row_slot;
104 struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sp;
105 int slot_dist;
107 tw_bucket = 1;
108 timer_active1 = timer_active2 = 0;
109 timer_active = 3;
110 slot_dist = tw->death_slot;
111 if(slot_dist > tcp_tw_death_row_slot)
112 slot_dist = (TCP_TWKILL_SLOTS - slot_dist) + tcp_tw_death_row_slot;
113 else
114 slot_dist = tcp_tw_death_row_slot - slot_dist;
115 timer_expires = jiffies + (slot_dist * TCP_TWKILL_PERIOD);
116 } else {
117 timer_active1 = tp->retransmit_timer.prev != NULL;
118 timer_active2 = sp->timer.prev != NULL;
119 timer_active = 0;
120 timer_expires = (unsigned) -1;
122 if (timer_active1 && tp->retransmit_timer.expires < timer_expires) {
123 timer_active = 1;
124 timer_expires = tp->retransmit_timer.expires;
126 if (timer_active2 && sp->timer.expires < timer_expires) {
127 timer_active = 2;
128 timer_expires = sp->timer.expires;
130 if(timer_active == 0)
131 timer_expires = jiffies;
132 sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
133 " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
134 i, src, srcp, dest, destp, sp->state,
135 (tw_bucket ?
137 (format == 0) ?
138 tp->write_seq-tp->snd_una : atomic_read(&sp->wmem_alloc)),
139 (tw_bucket ?
141 (format == 0) ?
142 tp->rcv_nxt-tp->copied_seq: atomic_read(&sp->rmem_alloc)),
143 timer_active, timer_expires-jiffies,
144 (tw_bucket ? 0 : tp->retransmits),
145 (!tw_bucket && sp->socket) ? sp->socket->inode->i_uid : 0,
146 (!tw_bucket && timer_active) ? sp->timeout : 0,
147 (!tw_bucket && sp->socket) ? sp->socket->inode->i_ino : 0);
151 * Get__netinfo returns the length of that string.
153 * KNOWN BUGS
154 * As in get_unix_netinfo, the buffer might be too small. If this
155 * happens, get__netinfo returns only part of the available infos.
157 * Assumes that buffer length is a multiply of 128 - if not it will
158 * write past the end.
160 static int
161 get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t offset, int length)
163 struct sock *sp, *next;
164 int len=0, i = 0;
165 off_t pos=0;
166 off_t begin;
167 char tmpbuf[129];
169 if (offset < 128)
170 len += sprintf(buffer, "%-127s\n",
171 " sl local_address rem_address st tx_queue "
172 "rx_queue tr tm->when retrnsmt uid timeout inode");
173 pos = 128;
174 SOCKHASH_LOCK_READ();
175 sp = pro->sklist_next;
176 while(sp != (struct sock *)pro) {
177 if (format == 0 && sp->state == TCP_LISTEN) {
178 struct open_request *req;
180 for (req = sp->tp_pinfo.af_tcp.syn_wait_queue; req;
181 i++, req = req->dl_next) {
182 if (req->sk)
183 continue;
184 pos += 128;
185 if (pos < offset)
186 continue;
187 get__openreq(sp, req, tmpbuf, i);
188 len += sprintf(buffer+len, "%-127s\n", tmpbuf);
189 if(len >= length)
190 goto out;
194 pos += 128;
195 if (pos < offset)
196 goto next;
198 get__sock(sp, tmpbuf, i, format);
200 len += sprintf(buffer+len, "%-127s\n", tmpbuf);
201 if(len >= length)
202 break;
203 next:
204 next = sp->sklist_next;
205 sp = next;
206 i++;
208 out:
209 SOCKHASH_UNLOCK_READ();
211 begin = len - (pos - offset);
212 *start = buffer + begin;
213 len -= begin;
214 if(len>length)
215 len = length;
216 if (len<0)
217 len = 0;
218 return len;
221 int tcp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
223 return get__netinfo(&tcp_prot, buffer,0, start, offset, length);
226 int udp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
228 return get__netinfo(&udp_prot, buffer,1, start, offset, length);
231 int raw_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
233 return get__netinfo(&raw_prot, buffer,1, start, offset, length);
237 * Report socket allocation statistics [mea@utu.fi]
239 int afinet_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
241 /* From net/socket.c */
242 extern int socket_get_info(char *, char **, off_t, int);
244 int len = socket_get_info(buffer,start,offset,length);
246 len += sprintf(buffer+len,"TCP: inuse %d highest %d\n",
247 tcp_prot.inuse, tcp_prot.highestinuse);
248 len += sprintf(buffer+len,"UDP: inuse %d highest %d\n",
249 udp_prot.inuse, udp_prot.highestinuse);
250 len += sprintf(buffer+len,"RAW: inuse %d highest %d\n",
251 raw_prot.inuse, raw_prot.highestinuse);
252 if (offset >= len)
254 *start = buffer;
255 return 0;
257 *start = buffer + offset;
258 len -= offset;
259 if (len > length)
260 len = length;
261 if (len < 0)
262 len = 0;
263 return len;
268 * Called from the PROCfs module. This outputs /proc/net/snmp.
271 int snmp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
273 extern struct tcp_mib tcp_statistics;
274 extern struct udp_mib udp_statistics;
275 int len;
277 extern unsigned long tcp_rx_miss, tcp_rx_hit1,tcp_rx_hit2;
280 len = sprintf (buffer,
281 "Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates\n"
282 "Ip: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
283 ip_statistics.IpForwarding, ip_statistics.IpDefaultTTL,
284 ip_statistics.IpInReceives, ip_statistics.IpInHdrErrors,
285 ip_statistics.IpInAddrErrors, ip_statistics.IpForwDatagrams,
286 ip_statistics.IpInUnknownProtos, ip_statistics.IpInDiscards,
287 ip_statistics.IpInDelivers, ip_statistics.IpOutRequests,
288 ip_statistics.IpOutDiscards, ip_statistics.IpOutNoRoutes,
289 ip_statistics.IpReasmTimeout, ip_statistics.IpReasmReqds,
290 ip_statistics.IpReasmOKs, ip_statistics.IpReasmFails,
291 ip_statistics.IpFragOKs, ip_statistics.IpFragFails,
292 ip_statistics.IpFragCreates);
294 len += sprintf (buffer + len,
295 "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"
296 "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",
297 icmp_statistics.IcmpInMsgs, icmp_statistics.IcmpInErrors,
298 icmp_statistics.IcmpInDestUnreachs, icmp_statistics.IcmpInTimeExcds,
299 icmp_statistics.IcmpInParmProbs, icmp_statistics.IcmpInSrcQuenchs,
300 icmp_statistics.IcmpInRedirects, icmp_statistics.IcmpInEchos,
301 icmp_statistics.IcmpInEchoReps, icmp_statistics.IcmpInTimestamps,
302 icmp_statistics.IcmpInTimestampReps, icmp_statistics.IcmpInAddrMasks,
303 icmp_statistics.IcmpInAddrMaskReps, icmp_statistics.IcmpOutMsgs,
304 icmp_statistics.IcmpOutErrors, icmp_statistics.IcmpOutDestUnreachs,
305 icmp_statistics.IcmpOutTimeExcds, icmp_statistics.IcmpOutParmProbs,
306 icmp_statistics.IcmpOutSrcQuenchs, icmp_statistics.IcmpOutRedirects,
307 icmp_statistics.IcmpOutEchos, icmp_statistics.IcmpOutEchoReps,
308 icmp_statistics.IcmpOutTimestamps, icmp_statistics.IcmpOutTimestampReps,
309 icmp_statistics.IcmpOutAddrMasks, icmp_statistics.IcmpOutAddrMaskReps);
311 len += sprintf (buffer + len,
312 "Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts\n"
313 "Tcp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
314 tcp_statistics.TcpRtoAlgorithm, tcp_statistics.TcpRtoMin,
315 tcp_statistics.TcpRtoMax, tcp_statistics.TcpMaxConn,
316 tcp_statistics.TcpActiveOpens, tcp_statistics.TcpPassiveOpens,
317 tcp_statistics.TcpAttemptFails, tcp_statistics.TcpEstabResets,
318 tcp_statistics.TcpCurrEstab, tcp_statistics.TcpInSegs,
319 tcp_statistics.TcpOutSegs, tcp_statistics.TcpRetransSegs,
320 tcp_statistics.TcpInErrs, tcp_statistics.TcpOutRsts);
322 len += sprintf (buffer + len,
323 "Udp: InDatagrams NoPorts InErrors OutDatagrams\nUdp: %lu %lu %lu %lu\n",
324 udp_statistics.UdpInDatagrams, udp_statistics.UdpNoPorts,
325 udp_statistics.UdpInErrors, udp_statistics.UdpOutDatagrams);
327 len += sprintf( buffer + len,
328 "TCP fast path RX: H2: %ul H1: %ul L: %ul\n",
329 tcp_rx_hit2,tcp_rx_hit1,tcp_rx_miss);
332 if (offset >= len)
334 *start = buffer;
335 return 0;
337 *start = buffer + offset;
338 len -= offset;
339 if (len > length)
340 len = length;
341 if (len < 0)
342 len = 0;
343 return len;
347 * Output /proc/net/netstat
350 int netstat_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
352 extern struct linux_mib net_statistics;
353 int len;
355 len = sprintf(buffer,
356 "TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
357 " EmbryonicRsts PruneCalled RcvPruned OfoPruned"
358 " OutOfWindowIcmps LockDroppedIcmps\n"
359 "TcpExt: %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
360 net_statistics.SyncookiesSent,
361 net_statistics.SyncookiesRecv,
362 net_statistics.SyncookiesFailed,
363 net_statistics.EmbryonicRsts,
364 net_statistics.PruneCalled,
365 net_statistics.RcvPruned,
366 net_statistics.OfoPruned,
367 net_statistics.OutOfWindowIcmps,
368 net_statistics.LockDroppedIcmps);
370 if (offset >= len)
372 *start = buffer;
373 return 0;
375 *start = buffer + offset;
376 len -= offset;
377 if (len > length)
378 len = length;
379 if (len < 0)
380 len = 0;
381 return len;