summaryrefslogtreecommitdiffstats
path: root/fs/proc/net.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc/net.c')
-rw-r--r--fs/proc/net.c300
1 files changed, 300 insertions, 0 deletions
diff --git a/fs/proc/net.c b/fs/proc/net.c
new file mode 100644
index 000000000..601f590d3
--- /dev/null
+++ b/fs/proc/net.c
@@ -0,0 +1,300 @@
+/*
+ * linux/fs/proc/net.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * gjh 3/'93 heim@peanuts.informatik.uni-tuebingen.de (Gerald J. Heim)
+ * most of this file is stolen from base.c
+ * it works, but you shouldn't use it as a guideline
+ * for new proc-fs entries. once i'll make it better.
+ * fvk 3/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
+ * cleaned up the whole thing, moved "net" specific code to
+ * the NET kernel layer (where it belonged in the first place).
+ * Michael K. Johnson (johnsonm@stolaf.edu) 3/93
+ * Added support from my previous inet.c. Cleaned things up
+ * quite a bit, modularized the code.
+ * fvk 4/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
+ * Renamed "route_get_info()" to "rt_get_info()" for consistency.
+ * Alan Cox (gw4pts@gw4pts.ampr.org) 4/94
+ * Dusted off the code and added IPX. Fixed the 4K limit.
+ * Erik Schoenfelder (schoenfr@ibr.cs.tu-bs.de)
+ * /proc/net/snmp.
+ *
+ * proc net directory handling functions
+ */
+#include <linux/autoconf.h>
+
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+/* forward references */
+static int proc_readnet(struct inode * inode, struct file * file,
+ char * buf, int count);
+static int proc_readnetdir(struct inode *, struct file *,
+ struct dirent *, int);
+static int proc_lookupnet(struct inode *,const char *,int,struct inode **);
+
+/* the get_*_info() functions are in the net code, and are configured
+ in via the standard mechanism... */
+extern int unix_get_info(char *, char **, off_t, int);
+#ifdef CONFIG_INET
+extern int tcp_get_info(char *, char **, off_t, int);
+extern int udp_get_info(char *, char **, off_t, int);
+extern int raw_get_info(char *, char **, off_t, int);
+extern int arp_get_info(char *, char **, off_t, int);
+extern int rarp_get_info(char *, char **, off_t, int);
+extern int dev_get_info(char *, char **, off_t, int);
+extern int rt_get_info(char *, char **, off_t, int);
+extern int snmp_get_info(char *, char **, off_t, int);
+#endif /* CONFIG_INET */
+#ifdef CONFIG_IPX
+extern int ipx_get_info(char *, char **, off_t, int);
+extern int ipx_rt_get_info(char *, char **, off_t, int);
+#endif /* CONFIG_IPX */
+#ifdef CONFIG_AX25
+extern int ax25_get_info(char *, char **, off_t, int);
+extern int ax25_rt_get_info(char *, char **, off_t, int);
+#ifdef CONFIG_NETROM
+extern int nr_get_info(char *, char **, off_t, int);
+extern int nr_nodes_get_info(char *, char **, off_t, int);
+extern int nr_neigh_get_info(char *, char **, off_t, int);
+#endif /* CONFIG_NETROM */
+#endif /* CONFIG_AX25 */
+
+
+static struct file_operations proc_net_operations = {
+ NULL, /* lseek - default */
+ proc_readnet, /* read - bad */
+ NULL, /* write - bad */
+ proc_readnetdir, /* readdir */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ NULL /* can't fsync */
+};
+
+/*
+ * proc directories can do almost nothing..
+ */
+struct inode_operations proc_net_inode_operations = {
+ &proc_net_operations, /* default net directory file-ops */
+ NULL, /* create */
+ proc_lookupnet, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+static struct proc_dir_entry net_dir[] = {
+ { PROC_NET, 1, "." },
+ { PROC_ROOT_INO, 2, ".." },
+ { PROC_NET_UNIX, 4, "unix" },
+#ifdef CONFIG_INET
+ { PROC_NET_ARP, 3, "arp" },
+ { PROC_NET_ROUTE, 5, "route" },
+ { PROC_NET_DEV, 3, "dev" },
+ { PROC_NET_RAW, 3, "raw" },
+ { PROC_NET_TCP, 3, "tcp" },
+ { PROC_NET_UDP, 3, "udp" },
+ { PROC_NET_SNMP, 4, "snmp" },
+#ifdef CONFIG_INET_RARP
+ { PROC_NET_RARP, 4, "rarp"},
+#endif
+#endif /* CONFIG_INET */
+#ifdef CONFIG_IPX
+ { PROC_NET_IPX_ROUTE, 9, "ipx_route" },
+ { PROC_NET_IPX, 3, "ipx" },
+#endif /* CONFIG_IPX */
+#ifdef CONFIG_AX25
+ { PROC_NET_AX25_ROUTE, 10, "ax25_route" },
+ { PROC_NET_AX25, 4, "ax25" },
+#ifdef CONFIG_NETROM
+ { PROC_NET_NR_NODES, 8, "nr_nodes" },
+ { PROC_NET_NR_NEIGH, 8, "nr_neigh" },
+ { PROC_NET_NR, 2, "nr" },
+#endif /* CONFIG_NETROM */
+#endif /* CONFIG_AX25 */
+ { 0, 0, NULL }
+};
+
+#define NR_NET_DIRENTRY ((sizeof (net_dir))/(sizeof (net_dir[0])) - 1)
+
+static int proc_lookupnet(struct inode * dir,const char * name, int len,
+ struct inode ** result)
+{
+ struct proc_dir_entry *de;
+
+ *result = NULL;
+ if (!dir)
+ return -ENOENT;
+ if (!S_ISDIR(dir->i_mode)) {
+ iput(dir);
+ return -ENOENT;
+ }
+ for (de = net_dir ; de->name ; de++) {
+ if (!proc_match(len, name, de))
+ continue;
+ *result = iget(dir->i_sb, de->low_ino);
+ iput(dir);
+ if (!*result)
+ return -ENOENT;
+ return 0;
+ }
+ return -ENOENT;
+}
+
+static int proc_readnetdir(struct inode * inode, struct file * filp,
+ struct dirent * dirent, int count)
+{
+ struct proc_dir_entry * de;
+ unsigned int ino;
+ int i,j;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -EBADF;
+ ino = inode->i_ino;
+ if (((unsigned) filp->f_pos) < NR_NET_DIRENTRY) {
+ de = net_dir + filp->f_pos;
+ filp->f_pos++;
+ i = de->namelen;
+ ino = de->low_ino;
+ put_fs_long(ino, &dirent->d_ino);
+ put_fs_word(i,&dirent->d_reclen);
+ put_fs_byte(0,i+dirent->d_name);
+ j = i;
+ while (i--)
+ put_fs_byte(de->name[i], i+dirent->d_name);
+ return j;
+ }
+ return 0;
+}
+
+
+#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
+
+static int proc_readnet(struct inode * inode, struct file * file,
+ char * buf, int count)
+{
+ char * page;
+ int length;
+ unsigned int ino;
+ int bytes=count;
+ int thistime;
+ int copied=0;
+ char *start;
+
+ if (count < 0)
+ return -EINVAL;
+ if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ ino = inode->i_ino;
+
+ while(bytes>0)
+ {
+ thistime=bytes;
+ if(bytes>PROC_BLOCK_SIZE)
+ thistime=PROC_BLOCK_SIZE;
+
+ switch (ino)
+ {
+ case PROC_NET_UNIX:
+ length = unix_get_info(page,&start,file->f_pos,thistime);
+ break;
+#ifdef CONFIG_INET
+ case PROC_NET_ARP:
+ length = arp_get_info(page,&start,file->f_pos,thistime);
+ break;
+ case PROC_NET_ROUTE:
+ length = rt_get_info(page,&start,file->f_pos,thistime);
+ break;
+ case PROC_NET_DEV:
+ length = dev_get_info(page,&start,file->f_pos,thistime);
+ break;
+ case PROC_NET_RAW:
+ length = raw_get_info(page,&start,file->f_pos,thistime);
+ break;
+ case PROC_NET_TCP:
+ length = tcp_get_info(page,&start,file->f_pos,thistime);
+ break;
+ case PROC_NET_UDP:
+ length = udp_get_info(page,&start,file->f_pos,thistime);
+ break;
+ case PROC_NET_SNMP:
+ length = snmp_get_info(page, &start, file->f_pos,thistime);
+ break;
+#ifdef CONFIG_INET_RARP
+ case PROC_NET_RARP:
+ length = rarp_get_info(page,&start,file->f_pos,thistime);
+ break;
+#endif /* CONFIG_INET_RARP */
+#endif /* CONFIG_INET */
+#ifdef CONFIG_IPX
+ case PROC_NET_IPX_ROUTE:
+ length = ipx_rt_get_info(page,&start,file->f_pos,thistime);
+ break;
+ case PROC_NET_IPX:
+ length = ipx_get_info(page,&start,file->f_pos,thistime);
+ break;
+#endif /* CONFIG_IPX */
+#ifdef CONFIG_AX25
+ case PROC_NET_AX25_ROUTE:
+ length = ax25_rt_get_info(page,&start,file->f_pos,thistime);
+ break;
+ case PROC_NET_AX25:
+ length = ax25_get_info(page,&start,file->f_pos,thistime);
+ break;
+#ifdef CONFIG_NETROM
+ case PROC_NET_NR_NODES:
+ length = nr_nodes_get_info(page,&start,file->f_pos,thistime);
+ break;
+ case PROC_NET_NR_NEIGH:
+ length = nr_neigh_get_info(page,&start,file->f_pos,thistime);
+ break;
+ case PROC_NET_NR:
+ length = nr_get_info(page,&start,file->f_pos,thistime);
+ break;
+#endif /* CONFIG_NETROM */
+#endif /* CONFIG_AX25 */
+
+ default:
+ free_page((unsigned long) page);
+ return -EBADF;
+ }
+
+ /*
+ * We have been given a non page aligned block of
+ * the data we asked for + a bit. We have been given
+ * the start pointer and we know the length..
+ */
+
+ if (length <= 0)
+ break;
+ /*
+ * Copy the bytes
+ */
+ memcpy_tofs(buf+copied, start, length);
+ file->f_pos+=length; /* Move down the file */
+ bytes-=length;
+ copied+=length;
+ if(length<thistime)
+ break; /* End of file */
+ }
+ free_page((unsigned long) page);
+ return copied;
+
+}