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.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>
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 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
,
63 (long unsigned int)req
->af
.v4_req
.rmt_addr
,
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
),
70 sk
->socket
? sk
->socket
->inode
->i_uid
: 0,
71 0, /* non standard timer */
72 0 /* open_requests have no inode */
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
;
83 unsigned long timer_expires
;
84 struct tcp_opt
*tp
= &sp
->tp_pinfo
.af_tcp
;
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
);
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
;
108 timer_active1
= timer_active2
= 0;
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
;
114 slot_dist
= tcp_tw_death_row_slot
- slot_dist
;
115 timer_expires
= jiffies
+ (slot_dist
* TCP_TWKILL_PERIOD
);
117 timer_active1
= tp
->retransmit_timer
.prev
!= NULL
;
118 timer_active2
= sp
->timer
.prev
!= NULL
;
120 timer_expires
= (unsigned) -1;
122 if (timer_active1
&& tp
->retransmit_timer
.expires
< timer_expires
) {
124 timer_expires
= tp
->retransmit_timer
.expires
;
126 if (timer_active2
&& sp
->timer
.expires
< timer_expires
) {
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
,
138 tp
->write_seq
-tp
->snd_una
: atomic_read(&sp
->wmem_alloc
)),
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.
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.
161 get__netinfo(struct proto
*pro
, char *buffer
, int format
, char **start
, off_t offset
, int length
)
163 struct sock
*sp
, *next
;
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");
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
) {
187 get__openreq(sp
, req
, tmpbuf
, i
);
188 len
+= sprintf(buffer
+len
, "%-127s\n", tmpbuf
);
198 get__sock(sp
, tmpbuf
, i
, format
);
200 len
+= sprintf(buffer
+len
, "%-127s\n", tmpbuf
);
204 next
= sp
->sklist_next
;
209 SOCKHASH_UNLOCK_READ();
211 begin
= len
- (pos
- offset
);
212 *start
= buffer
+ begin
;
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
);
257 *start
= buffer
+ offset
;
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
;
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);
337 *start
= buffer
+ offset
;
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
;
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
);
375 *start
= buffer
+ offset
;