root/fs/proc/net.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. proc_net_register
  2. proc_net_unregister
  3. dir_get_info
  4. proc_net_init
  5. proc_lookupnet
  6. proc_readnetdir
  7. proc_readnet

   1 /*
   2  *  linux/fs/proc/net.c
   3  *
   4  *  Copyright (C) 1991, 1992 Linus Torvalds
   5  *
   6  *  gjh 3/'93 heim@peanuts.informatik.uni-tuebingen.de (Gerald J. Heim)
   7  *            most of this file is stolen from base.c
   8  *            it works, but you shouldn't use it as a guideline
   9  *            for new proc-fs entries. once i'll make it better.
  10  * fvk 3/'93  waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
  11  *            cleaned up the whole thing, moved "net" specific code to
  12  *            the NET kernel layer (where it belonged in the first place).
  13  * Michael K. Johnson (johnsonm@stolaf.edu) 3/93
  14  *            Added support from my previous inet.c.  Cleaned things up
  15  *            quite a bit, modularized the code.
  16  * fvk 4/'93  waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
  17  *            Renamed "route_get_info()" to "rt_get_info()" for consistency.
  18  * Alan Cox (gw4pts@gw4pts.ampr.org) 4/94
  19  *            Dusted off the code and added IPX. Fixed the 4K limit.
  20  * Erik Schoenfelder (schoenfr@ibr.cs.tu-bs.de)
  21  *            /proc/net/snmp.
  22  * Alan Cox (gw4pts@gw4pts.ampr.org) 1/95
  23  *            Added Appletalk slots
  24  *
  25  *  proc net directory handling functions
  26  */
  27 #include <linux/autoconf.h>
  28 
  29 #include <asm/segment.h>
  30 
  31 #include <linux/errno.h>
  32 #include <linux/sched.h>
  33 #include <linux/proc_fs.h>
  34 #include <linux/stat.h>
  35 #include <linux/fcntl.h>
  36 #include <linux/config.h>
  37 #include <linux/mm.h>
  38 
  39 /* forward references */
  40 static int proc_readnet(struct inode * inode, struct file * file,
  41                          char * buf, int count);
  42 static int proc_readnetdir(struct inode *, struct file *,
  43                            void *, filldir_t filldir);
  44 static int proc_lookupnet(struct inode *,const char *,int,struct inode **);
  45 
  46 static struct file_operations proc_net_operations = {
  47         NULL,                   /* lseek - default */
  48         proc_readnet,           /* read - bad */
  49         NULL,                   /* write - bad */
  50         proc_readnetdir,        /* readdir */
  51         NULL,                   /* select - default */
  52         NULL,                   /* ioctl - default */
  53         NULL,                   /* mmap */
  54         NULL,                   /* no special open code */
  55         NULL,                   /* no special release code */
  56         NULL                    /* can't fsync */
  57 };
  58 
  59 /*
  60  * proc directories can do almost nothing..
  61  */
  62 struct inode_operations proc_net_inode_operations = {
  63         &proc_net_operations,   /* default net directory file-ops */
  64         NULL,                   /* create */
  65         proc_lookupnet,         /* lookup */
  66         NULL,                   /* link */
  67         NULL,                   /* unlink */
  68         NULL,                   /* symlink */
  69         NULL,                   /* mkdir */
  70         NULL,                   /* rmdir */
  71         NULL,                   /* mknod */
  72         NULL,                   /* rename */
  73         NULL,                   /* readlink */
  74         NULL,                   /* follow_link */
  75         NULL,                   /* bmap */
  76         NULL,                   /* truncate */
  77         NULL                    /* permission */
  78 };
  79 
  80 #define NR_MAX_PROC_NET_DIR 100
  81 static struct proc_dir_entry *net_dir[NR_MAX_PROC_NET_DIR] = {
  82         NULL,
  83 };
  84 
  85 static int nr_net_direntry = 0;
  86 
  87 int proc_net_register(struct proc_dir_entry *dp)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89         int i;
  90 
  91         for (i = 0; net_dir[i] != NULL; ++i ) ;
  92 
  93         if (i >= NR_MAX_PROC_NET_DIR)
  94           return -ENOMEM;
  95 
  96         net_dir[i] = dp;
  97         net_dir[i+1] = NULL; /* Just make sure.. */
  98         ++nr_net_direntry;
  99         return i;
 100 }
 101 
 102 int proc_net_unregister(int ino)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104         int i;
 105         for (i = 0; net_dir[i] != NULL && i < nr_net_direntry; ++i)
 106           if (net_dir[i]->low_ino == ino) {
 107             for ( ; net_dir[i] != NULL; ++i )
 108               net_dir[i] = net_dir[i+1];
 109             --nr_net_direntry;
 110             return 0;
 111           }
 112         return -ENOENT;
 113 }
 114 
 115 static int dir_get_info(char * a, char ** b, off_t d, int e, int f)
     /* [previous][next][first][last][top][bottom][index][help] */
 116 {
 117         return -EISDIR;
 118 }
 119 
 120 void proc_net_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122         static struct proc_dir_entry
 123           nd_thisdir = { PROC_NET, dir_get_info, 1, "." },
 124           nd_rootdir = { PROC_ROOT_INO, dir_get_info, 1, ".." };
 125         static int already = 0;
 126 
 127         if (already) return;
 128         already = 1;
 129 
 130         proc_net_register(&nd_thisdir);
 131         proc_net_register(&nd_rootdir);
 132 }
 133 
 134 
 135 static int proc_lookupnet(struct inode * dir,const char * name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 136                           struct inode ** result)
 137 {
 138         struct proc_dir_entry **de;
 139 
 140         *result = NULL;
 141         if (!dir)
 142                 return -ENOENT;
 143         if (!S_ISDIR(dir->i_mode)) {
 144                 iput(dir);
 145                 return -ENOENT;
 146         }
 147         for (de = net_dir ; (*de)->name ; de++) {
 148                 if (!proc_match(len, name, *de))
 149                         continue;
 150                 *result = iget(dir->i_sb, (*de)->low_ino);
 151                 iput(dir);
 152                 if (!*result)
 153                         return -ENOENT;
 154                 return 0;
 155         }
 156         iput(dir);
 157         return -ENOENT;
 158 }
 159 
 160 static int proc_readnetdir(struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 161         void * dirent, filldir_t filldir)
 162 {
 163         struct proc_dir_entry * de;
 164         unsigned int ino;
 165 
 166         if (!inode || !S_ISDIR(inode->i_mode))
 167                 return -EBADF;
 168         ino = inode->i_ino;
 169         while (((unsigned) filp->f_pos) < nr_net_direntry) {
 170                 de = net_dir[filp->f_pos];
 171                 if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino) < 0)
 172                         break;
 173                 filp->f_pos++;
 174         }
 175         return 0;
 176 }
 177 
 178 
 179 #define PROC_BLOCK_SIZE (3*1024)                /* 4K page size but our output routines use some slack for overruns */
 180 
 181 static int proc_readnet(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 182                         char * buf, int count)
 183 {
 184         char * page;
 185         unsigned int ino;
 186         int bytes=count;
 187         int i;
 188         int copied=0;
 189         char *start;
 190         struct proc_dir_entry * dp;
 191 
 192         if (count < 0)
 193                 return -EINVAL;
 194         ino = inode->i_ino;
 195         for (i = 0; ;i++) {
 196                 if (i >= NR_MAX_PROC_NET_DIR || (dp = net_dir[i]) == NULL)
 197                         return -EBADF;
 198                 if (dp->low_ino == ino)
 199                         break;
 200         }
 201         if (!(page = (char*) __get_free_page(GFP_KERNEL)))
 202                 return -ENOMEM;
 203 
 204         while (bytes>0)
 205         {
 206                 int length, thistime=bytes;
 207                 if (bytes > PROC_BLOCK_SIZE)
 208                         thistime=PROC_BLOCK_SIZE;
 209 
 210                 length = dp->get_info(page, &start,
 211                                       file->f_pos,
 212                                       thistime,
 213                                       (file->f_flags & O_ACCMODE) == O_RDWR);
 214 
 215                 /*
 216                  *      We have been given a non page aligned block of
 217                  *      the data we asked for + a bit. We have been given
 218                  *      the start pointer and we know the length.. 
 219                  */
 220 
 221                 if (length <= 0)
 222                         break;
 223                 /*
 224                  *      Copy the bytes
 225                  */
 226                 memcpy_tofs(buf+copied, start, length);
 227                 file->f_pos += length;  /* Move down the file */
 228                 bytes  -= length;
 229                 copied += length;
 230                 if (length<thistime)
 231                         break;  /* End of file */
 232         }
 233         free_page((unsigned long) page);
 234         return copied;
 235 }

/* [previous][next][first][last][top][bottom][index][help] */