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
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>
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>
41 #include <linux/param.h>
42 #include <linux/inet.h>
43 #include <linux/netdevice.h>
46 #include <net/protocol.h>
49 #include <linux/skbuff.h>
53 /* Format a single open_request into tmpbuf. */
54 static inline void get__openreq(struct sock
*sk
, struct open_request
*req
,
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
,
64 (long unsigned int)req
->af
.v4_req
.rmt_addr
,
67 0,0, /* use sizeof(struct open_request) here? */
68 0, (unsigned long)(req
->expires
- jiffies
), /* ??? */
70 sk
->socket
? sk
->socket
->inode
->i_uid
: 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
;
82 unsigned long timer_expires
;
83 struct tcp_opt
*tp
= &sp
->tp_pinfo
.af_tcp
;
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
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
;
107 timer_active1
= timer_active2
= 0;
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
;
113 slot_dist
= tcp_tw_death_row_slot
- slot_dist
;
114 timer_expires
= jiffies
+ (slot_dist
* TCP_TWKILL_PERIOD
);
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;
121 timer_expires
= (unsigned) -1;
123 if (timer_active1
&& tp
->retransmit_timer
.expires
< timer_expires
) {
125 timer_expires
= tp
->retransmit_timer
.expires
;
127 if (timer_active2
&& sp
->timer
.expires
< timer_expires
) {
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
,
139 tp
->write_seq
-tp
->snd_una
: atomic_read(&sp
->wmem_alloc
)),
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.
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.
162 get__netinfo(struct proto
*pro
, char *buffer
, int format
, char **start
, off_t offset
, int length
)
164 struct sock
*sp
, *next
;
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");
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.]
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
) {
197 get__openreq(sp
, req
, tmpbuf
, i
);
198 len
+= sprintf(buffer
+len
, "%-127s\n", tmpbuf
);
208 get__sock(sp
, tmpbuf
, i
, format
);
210 len
+= sprintf(buffer
+len
, "%-127s\n", tmpbuf
);
214 next
= sp
->sklist_next
;
220 begin
= len
- (pos
- offset
);
221 *start
= buffer
+ begin
;
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
);
264 *start
= buffer
+ offset
;
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
;
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);
342 *start
= buffer
+ offset
;
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
;
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
);
375 *start
= buffer
+ offset
;