[PATCH] new helpers for /proc
[opensuse:kernel.git] / net / wanrouter / wanproc.c
1 /*****************************************************************************
2 * wanproc.c     WAN Router Module. /proc filesystem interface.
3 *
4 *               This module is completely hardware-independent and provides
5 *               access to the router using Linux /proc filesystem.
6 *
7 * Author:       Gideon Hack     
8 *
9 * Copyright:    (c) 1995-1999 Sangoma Technologies Inc.
10 *
11 *               This program is free software; you can redistribute it and/or
12 *               modify it under the terms of the GNU General Public License
13 *               as published by the Free Software Foundation; either version
14 *               2 of the License, or (at your option) any later version.
15 * ============================================================================
16 * Jun 02, 1999  Gideon Hack     Updates for Linux 2.2.X kernels.
17 * Jun 29, 1997  Alan Cox        Merged with 1.0.3 vendor code
18 * Jan 29, 1997  Gene Kozin      v1.0.1. Implemented /proc read routines
19 * Jan 30, 1997  Alan Cox        Hacked around for 2.1
20 * Dec 13, 1996  Gene Kozin      Initial version (based on Sangoma's WANPIPE)
21 *****************************************************************************/
22
23 #include <linux/version.h>
24 #include <linux/config.h>
25 #include <linux/stddef.h>       /* offsetof(), etc. */
26 #include <linux/errno.h>        /* return codes */
27 #include <linux/kernel.h>
28 #include <linux/slab.h> /* kmalloc(), kfree() */
29 #include <linux/mm.h>           /* verify_area(), etc. */
30 #include <linux/string.h>       /* inline mem*, str* functions */
31 #include <asm/byteorder.h>      /* htons(), etc. */
32 #include <asm/io.h>
33 #include <linux/wanrouter.h>    /* WAN router API definitions */
34 #include <linux/seq_file.h>
35 #include <linux/smp_lock.h>
36 #include <linux/init.h> /* __initfunc et al. */
37 #include <asm/uaccess.h>       /* copy_to_user */
38
39 #define PROC_STATS_FORMAT "%30s: %12lu\n"
40
41 /****** Defines and Macros **************************************************/
42
43 #define PROT_DECODE(prot) ((prot == WANCONFIG_FR) ? " FR" :\
44                               (prot == WANCONFIG_X25) ? " X25" : \
45                                  (prot == WANCONFIG_PPP) ? " PPP" : \
46                                     (prot == WANCONFIG_CHDLC) ? " CHDLC": \
47                                        (prot == WANCONFIG_MPPP) ? " MPPP" : \
48                                            " Unknown" )
49         
50 /****** Data Types **********************************************************/
51
52 typedef struct wan_stat_entry
53 {
54         struct wan_stat_entry *next;
55         char *description;              /* description string */
56         void *data;                     /* -> data */
57         unsigned data_type;             /* data type */
58 } wan_stat_entry_t;
59
60 /****** Function Prototypes *************************************************/
61
62 #ifdef CONFIG_PROC_FS
63
64 /* Proc filesystem interface */
65 static int router_proc_perms(struct inode *, int);
66
67 /* Miscellaneous */
68
69 /*
70  *      Structures for interfacing with the /proc filesystem.
71  *      Router creates its own directory /proc/net/router with the folowing
72  *      entries:
73  *      config          device configuration
74  *      status          global device statistics
75  *      <device>        entry for each WAN device
76  */
77
78 /*
79  *      Generic /proc/net/router/<file> file and inode operations 
80  */
81
82 static struct inode_operations router_inode =
83 {
84         permission:     router_proc_perms,
85 };
86
87 /*
88  *      /proc/net/router 
89  */
90
91 static struct proc_dir_entry *proc_router;
92
93 /* Strings */
94
95 /*
96  *      Interface functions
97  */
98
99 /****** Proc filesystem entry points ****************************************/
100
101 /*
102  *      Verify access rights.
103  */
104
105 static int router_proc_perms (struct inode* inode, int op)
106 {
107         return 0;
108 }
109
110 /*
111  *      Iterator
112  */
113 static void *r_start(struct seq_file *m, loff_t *pos)
114 {
115         wan_device_t *wandev;
116         loff_t l = *pos;
117
118         lock_kernel();
119         if (!l--)
120                 return (void *)1;
121         for (wandev = router_devlist; l-- && wandev; wandev = wandev->next)
122                 ;
123         return wandev;
124 }
125 static void *r_next(struct seq_file *m, void *v, loff_t *pos)
126 {
127         wan_device_t *wandev = v;
128         (*pos)++;
129         return (v == (void *)1) ? router_devlist : wandev->next;
130 }
131 static void r_stop(struct seq_file *m, void *v)
132 {
133         unlock_kernel();
134 }
135
136 static int config_show(struct seq_file *m, void *v)
137 {
138         wan_device_t *p = v;
139         if (v == (void *)1) {
140                 seq_puts(m, "Device name    | port |IRQ|DMA|  mem.addr  |");
141                 seq_puts(m, "mem.size|option1|option2|option3|option4\n");
142                 return 0;
143         }
144         if (!p->state)
145                 return 0;
146         seq_printf(m, "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n",
147                         p->name, p->ioport, p->irq, p->dma, p->maddr, p->msize,
148                         p->hw_opt[0], p->hw_opt[1], p->hw_opt[2], p->hw_opt[3]);
149         return 0;
150 }
151
152 static int status_show(struct seq_file *m, void *v)
153 {
154         wan_device_t *p = v;
155         if (v == (void *)1) {
156                 seq_puts(m, "Device name    |protocol|station|interface|");
157                 seq_puts(m, "clocking|baud rate| MTU |ndev|link state\n");
158                 return 0;
159         }
160         if (!p->state)
161                 return 0;
162         seq_printf(m, "%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |",
163                 p->name,
164                 PROT_DECODE(p->config_id),
165                 p->config_id == WANCONFIG_FR ? 
166                         (p->station ? " Node" : " CPE") :
167                         (p->config_id == WANCONFIG_X25 ?
168                         (p->station ? " DCE" : " DTE") :
169                         (" N/A")),
170                 p->interface ? " V.35" : " RS-232",
171                 p->clocking ? "internal" : "external",
172                 p->bps,
173                 p->mtu,
174                 p->ndev);
175
176         switch (p->state) {
177         case WAN_UNCONFIGURED:
178                 seq_printf(m, "%-12s\n", "unconfigured");
179                 break;
180         case WAN_DISCONNECTED:
181                 seq_printf(m, "%-12s\n", "disconnected");
182                 break;
183         case WAN_CONNECTING:
184                 seq_printf(m, "%-12s\n", "connecting");
185                 break;
186         case WAN_CONNECTED:
187                 seq_printf(m, "%-12s\n", "connected");
188                 break;
189         default:
190                 seq_printf(m, "%-12s\n", "invalid");
191                 break;
192         }
193         return 0;
194 }
195
196 static struct seq_operations config_op = {
197         start:  r_start,
198         next:   r_next,
199         stop:   r_stop,
200         show:   config_show
201 };
202
203 static struct seq_operations status_op = {
204         start:  r_start,
205         next:   r_next,
206         stop:   r_stop,
207         show:   status_show
208 };
209
210 static int config_open(struct inode *inode, struct file *file)
211 {
212         return seq_open(file, &config_op);
213 }
214
215 static int status_open(struct inode *inode, struct file *file)
216 {
217         return seq_open(file, &status_op);
218 }
219
220 static struct file_operations config_fops =
221 {
222         open:           config_open,
223         read:           seq_read,
224         llseek:         seq_lseek,
225         release:        seq_release,
226 };
227
228 static struct file_operations status_fops =
229 {
230         open:           status_open,
231         read:           seq_read,
232         llseek:         seq_lseek,
233         release:        seq_release,
234 };
235
236 static int wandev_show(struct seq_file *m, void *v)
237 {
238         wan_device_t *wandev = v;
239
240         if (wandev->magic != ROUTER_MAGIC)
241                 return 0;
242
243         if (!wandev->state) {
244                 seq_puts(m, "device is not configured!\n");
245                 return 0;
246         }
247
248         /* Update device statistics */
249         if (wandev->update) {
250                 int err = wandev->update(wandev);
251                 if (err == -EAGAIN) {
252                         seq_printf(m, "Device is busy!\n");
253                         return 0;
254                 }
255                 if (err) {
256                         seq_printf(m, "Device is not configured!\n");
257                         return 0;
258                 }
259         }
260
261         seq_printf(m, PROC_STATS_FORMAT,
262                 "total packets received", wandev->stats.rx_packets);
263         seq_printf(m, PROC_STATS_FORMAT,
264                 "total packets transmitted", wandev->stats.tx_packets);
265         seq_printf(m, PROC_STATS_FORMAT,
266                 "total bytes received", wandev->stats.rx_bytes);
267         seq_printf(m, PROC_STATS_FORMAT,
268                 "total bytes transmitted", wandev->stats.tx_bytes);
269         seq_printf(m, PROC_STATS_FORMAT,
270                 "bad packets received", wandev->stats.rx_errors);
271         seq_printf(m, PROC_STATS_FORMAT,
272                 "packet transmit problems", wandev->stats.tx_errors);
273         seq_printf(m, PROC_STATS_FORMAT,
274                 "received frames dropped", wandev->stats.rx_dropped);
275         seq_printf(m, PROC_STATS_FORMAT,
276                 "transmit frames dropped", wandev->stats.tx_dropped);
277         seq_printf(m, PROC_STATS_FORMAT,
278                 "multicast packets received", wandev->stats.multicast);
279         seq_printf(m, PROC_STATS_FORMAT,
280                 "transmit collisions", wandev->stats.collisions);
281         seq_printf(m, PROC_STATS_FORMAT,
282                 "receive length errors", wandev->stats.rx_length_errors);
283         seq_printf(m, PROC_STATS_FORMAT,
284                 "receiver overrun errors", wandev->stats.rx_over_errors);
285         seq_printf(m, PROC_STATS_FORMAT,
286                 "CRC errors", wandev->stats.rx_crc_errors);
287         seq_printf(m, PROC_STATS_FORMAT,
288                 "frame format errors (aborts)", wandev->stats.rx_frame_errors);
289         seq_printf(m, PROC_STATS_FORMAT,
290                 "receiver fifo overrun", wandev->stats.rx_fifo_errors);
291         seq_printf(m, PROC_STATS_FORMAT,
292                 "receiver missed packet", wandev->stats.rx_missed_errors);
293         seq_printf(m, PROC_STATS_FORMAT,
294                 "aborted frames transmitted", wandev->stats.tx_aborted_errors);
295         return 0;
296 }
297
298 static int wandev_open(struct inode *inode, struct file *file)
299 {
300         return single_open(file, wandev_show, PDE(inode)->data);
301 }
302
303 static struct file_operations wandev_fops =
304 {
305         open:           wandev_open,
306         read:           seq_read,
307         llseek:         seq_lseek,
308         release:        single_release,
309         ioctl:          wanrouter_ioctl,
310 };
311
312 /*
313  *      Initialize router proc interface.
314  */
315
316 int __init wanrouter_proc_init (void)
317 {
318         struct proc_dir_entry *p;
319         proc_router = proc_mkdir(ROUTER_NAME, proc_net);
320         if (!proc_router)
321                 goto fail;
322
323         p = create_proc_entry("config",0,proc_router);
324         if (!p)
325                 goto fail_config;
326         p->proc_fops = &config_fops;
327         p->proc_iops = &router_inode;
328         p = create_proc_entry("status",0,proc_router);
329         if (!p)
330                 goto fail_stat;
331         p->proc_fops = &status_fops;
332         p->proc_iops = &router_inode;
333         return 0;
334 fail_stat:
335         remove_proc_entry("config", proc_router);
336 fail_config:
337         remove_proc_entry(ROUTER_NAME, proc_net);
338 fail:
339         return -ENOMEM;
340 }
341
342 /*
343  *      Clean up router proc interface.
344  */
345
346 void wanrouter_proc_cleanup (void)
347 {
348         remove_proc_entry("config", proc_router);
349         remove_proc_entry("status", proc_router);
350         remove_proc_entry(ROUTER_NAME,proc_net);
351 }
352
353 /*
354  *      Add directory entry for WAN device.
355  */
356
357 int wanrouter_proc_add (wan_device_t* wandev)
358 {
359         if (wandev->magic != ROUTER_MAGIC)
360                 return -EINVAL;
361                 
362         wandev->dent = create_proc_entry(wandev->name, 0, proc_router);
363         if (!wandev->dent)
364                 return -ENOMEM;
365         wandev->dent->proc_fops = &wandev_fops;
366         wandev->dent->proc_iops = &router_inode;
367         wandev->dent->data      = wandev;
368         return 0;
369 }
370
371 /*
372  *      Delete directory entry for WAN device.
373  */
374  
375 int wanrouter_proc_delete(wan_device_t* wandev)
376 {
377         if (wandev->magic != ROUTER_MAGIC)
378                 return -EINVAL;
379         remove_proc_entry(wandev->name, proc_router);
380         return 0;
381 }
382
383 #else
384
385 /*
386  *      No /proc - output stubs
387  */
388
389 int __init wanrouter_proc_init(void)
390 {
391         return 0;
392 }
393
394 void wanrouter_proc_cleanup(void)
395 {
396 }
397
398 int wanrouter_proc_add(wan_device_t *wandev)
399 {
400         return 0;
401 }
402
403 int wanrouter_proc_delete(wan_device_t *wandev)
404 {
405         return 0;
406 }
407
408 #endif
409
410 /*
411  *      End
412  */
413