Import 2.1.120pre1
[davej-history.git] / net / ipv4 / proc.c
blob6f06f434582b6f4c9599d44343b6d94a717bbcf2
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.31 1998/07/29 20:09:25 freitag 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 /* FIXME: I'm not sure if the timer fields are correct. */
59 sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
60 " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu",
62 (long unsigned int)req->af.v4_req.loc_addr,
63 ntohs(sk->sport),
64 (long unsigned int)req->af.v4_req.rmt_addr,
65 req->rmt_port,
66 TCP_SYN_RECV,
67 0,0, /* use sizeof(struct open_request) here? */
68 0, (unsigned long)(req->expires - jiffies), /* ??? */
69 req->retrans,
70 sk->socket ? sk->socket->inode->i_uid : 0,
71 0, /* ??? */
72 sk->socket ? sk->socket->inode->i_ino:0);
75 /* Format a single socket into tmpbuf. */
76 static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format)
78 unsigned long dest, src;
79 unsigned short destp, srcp;
80 int timer_active, timer_active1, timer_active2;
81 int tw_bucket = 0;
82 unsigned long timer_expires;
83 struct tcp_opt *tp = &sp->tp_pinfo.af_tcp;
85 dest = sp->daddr;
86 src = sp->rcv_saddr;
87 destp = sp->dport;
88 srcp = sp->sport;
90 /* FIXME: The fact that retransmit_timer occurs as a field
91 * in two different parts of the socket structure is,
92 * to say the least, confusing. This code now uses the
93 * right retransmit_timer variable, but I'm not sure
94 * the rest of the timer stuff is still correct.
95 * In particular I'm not sure what the timeout value
96 * is suppose to reflect (as opposed to tm->when). -- erics
99 destp = ntohs(destp);
100 srcp = ntohs(srcp);
101 if((format == 0) && (sp->state == TCP_TIME_WAIT)) {
102 extern int tcp_tw_death_row_slot;
103 struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sp;
104 int slot_dist;
106 tw_bucket = 1;
107 timer_active1 = timer_active2 = 0;
108 timer_active = 3;
109 slot_dist = tw->death_slot;
110 if(slot_dist > tcp_tw_death_row_slot)
111 slot_dist = (TCP_TWKILL_SLOTS - slot_dist) + tcp_tw_death_row_slot;
112 else
113 slot_dist = tcp_tw_death_row_slot - slot_dist;
114 timer_expires = jiffies + (slot_dist * TCP_TWKILL_PERIOD);
115 } else {
116 timer_active1 = del_timer(&tp->retransmit_timer);
117 timer_active2 = del_timer(&sp->timer);
118 if (!timer_active1) tp->retransmit_timer.expires=0;
119 if (!timer_active2) sp->timer.expires=0;
120 timer_active = 0;
121 timer_expires = (unsigned) -1;
123 if (timer_active1 && tp->retransmit_timer.expires < timer_expires) {
124 timer_active = 1;
125 timer_expires = tp->retransmit_timer.expires;
127 if (timer_active2 && sp->timer.expires < timer_expires) {
128 timer_active = 2;
129 timer_expires = sp->timer.expires;
131 if(timer_active == 0)
132 timer_expires = jiffies;
133 sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
134 " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
135 i, src, srcp, dest, destp, sp->state,
136 (tw_bucket ?
138 (format == 0) ?
139 tp->write_seq-tp->snd_una : atomic_read(&sp->wmem_alloc)),
140 (tw_bucket ?
142 (format == 0) ?
143 tp->rcv_nxt-tp->copied_seq: atomic_read(&sp->rmem_alloc)),
144 timer_active, timer_expires-jiffies,
145 (tw_bucket ? 0 : tp->retransmits),
146 (!tw_bucket && sp->socket) ? sp->socket->inode->i_uid : 0,
147 (!tw_bucket && timer_active) ? sp->timeout : 0,
148 (!tw_bucket && sp->socket) ? sp->socket->inode->i_ino : 0);
150 if (timer_active1) add_timer(&tp->retransmit_timer);
151 if (timer_active2) add_timer(&sp->timer);
155 * Get__netinfo returns the length of that string.
157 * KNOWN BUGS
158 * As in get_unix_netinfo, the buffer might be too small. If this
159 * happens, get__netinfo returns only part of the available infos.
161 static int
162 get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t offset, int length)
164 struct sock *sp, *next;
165 int len=0, i = 0;
166 off_t pos=0;
167 off_t begin;
168 char tmpbuf[129];
170 if (offset < 128)
171 len += sprintf(buffer, "%-127s\n",
172 " sl local_address rem_address st tx_queue "
173 "rx_queue tr tm->when retrnsmt uid timeout inode");
174 pos = 128;
176 * This was very pretty but didn't work when a socket is destroyed
177 * at the wrong moment (eg a syn recv socket getting a reset), or
178 * a memory timer destroy. Instead of playing with timers we just
179 * concede defeat and do a start_bh_atomic().
180 * Why not just use lock_sock()? As far as I can see all timer routines
181 * check for sock_readers before doing anything. -AK
182 * [Disabled for now again, because it hard-locked my machine, and there
183 * is an theoretical situation then, where an user could prevent
184 * sockets from being destroyed by constantly reading /proc/net/tcp.]
186 SOCKHASH_LOCK();
187 sp = pro->sklist_next;
188 while(sp != (struct sock *)pro) {
189 if (format == 0 && sp->state == TCP_LISTEN) {
190 struct open_request *req;
192 for (req = sp->tp_pinfo.af_tcp.syn_wait_queue; req;
193 i++, req = req->dl_next) {
194 pos += 128;
195 if (pos < offset)
196 continue;
197 get__openreq(sp, req, tmpbuf, i);
198 len += sprintf(buffer+len, "%-127s\n", tmpbuf);
199 if(len >= length)
200 break;
204 pos += 128;
205 if (pos < offset)
206 goto next;
208 get__sock(sp, tmpbuf, i, format);
210 len += sprintf(buffer+len, "%-127s\n", tmpbuf);
211 if(len >= length)
212 break;
213 next:
214 next = sp->sklist_next;
215 sp = next;
216 i++;
218 SOCKHASH_UNLOCK();
220 begin = len - (pos - offset);
221 *start = buffer + begin;
222 len -= begin;
223 if(len>length)
224 len = length;
225 return len;
228 int tcp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
230 return get__netinfo(&tcp_prot, buffer,0, start, offset, length);
233 int udp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
235 return get__netinfo(&udp_prot, buffer,1, start, offset, length);
238 int raw_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
240 return get__netinfo(&raw_prot, buffer,1, start, offset, length);
244 * Report socket allocation statistics [mea@utu.fi]
246 int afinet_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
248 /* From net/socket.c */
249 extern int socket_get_info(char *, char **, off_t, int);
251 int len = socket_get_info(buffer,start,offset,length);
253 len += sprintf(buffer+len,"TCP: inuse %d highest %d\n",
254 tcp_prot.inuse, tcp_prot.highestinuse);
255 len += sprintf(buffer+len,"UDP: inuse %d highest %d\n",
256 udp_prot.inuse, udp_prot.highestinuse);
257 len += sprintf(buffer+len,"RAW: inuse %d highest %d\n",
258 raw_prot.inuse, raw_prot.highestinuse);
259 if (offset >= len)
261 *start = buffer;
262 return 0;
264 *start = buffer + offset;
265 len -= offset;
266 if (len > length)
267 len = length;
268 return len;
273 * Called from the PROCfs module. This outputs /proc/net/snmp.
276 int snmp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
278 extern struct tcp_mib tcp_statistics;
279 extern struct udp_mib udp_statistics;
280 int len;
282 extern unsigned long tcp_rx_miss, tcp_rx_hit1,tcp_rx_hit2;
285 len = sprintf (buffer,
286 "Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates\n"
287 "Ip: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
288 ip_statistics.IpForwarding, ip_statistics.IpDefaultTTL,
289 ip_statistics.IpInReceives, ip_statistics.IpInHdrErrors,
290 ip_statistics.IpInAddrErrors, ip_statistics.IpForwDatagrams,
291 ip_statistics.IpInUnknownProtos, ip_statistics.IpInDiscards,
292 ip_statistics.IpInDelivers, ip_statistics.IpOutRequests,
293 ip_statistics.IpOutDiscards, ip_statistics.IpOutNoRoutes,
294 ip_statistics.IpReasmTimeout, ip_statistics.IpReasmReqds,
295 ip_statistics.IpReasmOKs, ip_statistics.IpReasmFails,
296 ip_statistics.IpFragOKs, ip_statistics.IpFragFails,
297 ip_statistics.IpFragCreates);
299 len += sprintf (buffer + len,
300 "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"
301 "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",
302 icmp_statistics.IcmpInMsgs, icmp_statistics.IcmpInErrors,
303 icmp_statistics.IcmpInDestUnreachs, icmp_statistics.IcmpInTimeExcds,
304 icmp_statistics.IcmpInParmProbs, icmp_statistics.IcmpInSrcQuenchs,
305 icmp_statistics.IcmpInRedirects, icmp_statistics.IcmpInEchos,
306 icmp_statistics.IcmpInEchoReps, icmp_statistics.IcmpInTimestamps,
307 icmp_statistics.IcmpInTimestampReps, icmp_statistics.IcmpInAddrMasks,
308 icmp_statistics.IcmpInAddrMaskReps, icmp_statistics.IcmpOutMsgs,
309 icmp_statistics.IcmpOutErrors, icmp_statistics.IcmpOutDestUnreachs,
310 icmp_statistics.IcmpOutTimeExcds, icmp_statistics.IcmpOutParmProbs,
311 icmp_statistics.IcmpOutSrcQuenchs, icmp_statistics.IcmpOutRedirects,
312 icmp_statistics.IcmpOutEchos, icmp_statistics.IcmpOutEchoReps,
313 icmp_statistics.IcmpOutTimestamps, icmp_statistics.IcmpOutTimestampReps,
314 icmp_statistics.IcmpOutAddrMasks, icmp_statistics.IcmpOutAddrMaskReps);
316 len += sprintf (buffer + len,
317 "Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts\n"
318 "Tcp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
319 tcp_statistics.TcpRtoAlgorithm, tcp_statistics.TcpRtoMin,
320 tcp_statistics.TcpRtoMax, tcp_statistics.TcpMaxConn,
321 tcp_statistics.TcpActiveOpens, tcp_statistics.TcpPassiveOpens,
322 tcp_statistics.TcpAttemptFails, tcp_statistics.TcpEstabResets,
323 tcp_statistics.TcpCurrEstab, tcp_statistics.TcpInSegs,
324 tcp_statistics.TcpOutSegs, tcp_statistics.TcpRetransSegs,
325 tcp_statistics.TcpInErrs, tcp_statistics.TcpOutRsts);
327 len += sprintf (buffer + len,
328 "Udp: InDatagrams NoPorts InErrors OutDatagrams\nUdp: %lu %lu %lu %lu\n",
329 udp_statistics.UdpInDatagrams, udp_statistics.UdpNoPorts,
330 udp_statistics.UdpInErrors, udp_statistics.UdpOutDatagrams);
332 len += sprintf( buffer + len,
333 "TCP fast path RX: H2: %ul H1: %ul L: %ul\n",
334 tcp_rx_hit2,tcp_rx_hit1,tcp_rx_miss);
337 if (offset >= len)
339 *start = buffer;
340 return 0;
342 *start = buffer + offset;
343 len -= offset;
344 if (len > length)
345 len = length;
346 return len;
350 * Output /proc/net/netstat
353 int netstat_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
355 extern struct linux_mib net_statistics;
356 int len;
358 len = sprintf(buffer,
359 "TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
360 " EmbryonicRsts PruneCalled RcvPruned OfoPruned\n"
361 "TcpExt: %lu %lu %lu %lu %lu %lu %lu\n",
362 net_statistics.SyncookiesSent,
363 net_statistics.SyncookiesRecv,
364 net_statistics.SyncookiesFailed,
365 net_statistics.EmbryonicRsts,
366 net_statistics.PruneCalled,
367 net_statistics.RcvPruned,
368 net_statistics.OfoPruned);
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 return len;