/* * 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. * * Version: @(#)proc.c 1.0.5 05/27/93 * * Authors: Fred N. van Kempen, * Gerald J. Heim, * Fred Baumgarten, * * Fixes: * Alan Cox : UDP sockets show the rxqueue/txqueue * using hint flag for the netinfo. * Pauline Middelink : Pidentd support * Alan Cox : Make /proc safer. * * To Do: * Put the creating userid in the proc/net/... files. This will * allow us to write an RFC931 daemon for Linux * * 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 #include #include #include #include #include #include #include #include "inet.h" #include "dev.h" #include "ip.h" #include "protocol.h" #include "tcp.h" #include "udp.h" #include "skbuff.h" #include "sock.h" #include "raw.h" /* * 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. */ static int get__netinfo(struct proto *pro, char *buffer, int format) { struct sock **s_array; struct sock *sp; char *pos=buffer; int i; int timer_active; unsigned long dest, src; unsigned short destp, srcp; s_array = pro->sock_array; pos+=sprintf(pos, "sl local_address rem_address st tx_queue rx_queue tr tm->when uid\n"); /* * 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(). */ for(i = 0; i < SOCK_ARRAY_SIZE; i++) { cli(); sp = s_array[i]; while(sp != NULL) { 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); timer_active = del_timer(&sp->timer); if (!timer_active) sp->timer.expires = 0; pos+=sprintf(pos, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d\n", i, src, srcp, dest, destp, sp->state, format==0?sp->send_seq-sp->rcv_ack_seq:sp->rmem_alloc, format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc, timer_active, sp->timer.expires, (unsigned) sp->retransmits, SOCK_INODE(sp->socket)->i_uid); if (timer_active) add_timer(&sp->timer); /* Is place in buffer too rare? then abort. */ if (pos > buffer+PAGE_SIZE-80) { printk("oops, too many %s sockets for netinfo.\n", pro->name); return(strlen(buffer)); } /* * 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; } 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 its not as bad as it looks */ } return(strlen(buffer)); } int tcp_get_info(char *buffer) { return get__netinfo(&tcp_prot, buffer,0); } int udp_get_info(char *buffer) { return get__netinfo(&udp_prot, buffer,1); } int raw_get_info(char *buffer) { return get__netinfo(&raw_prot, buffer,1); }