v2.4.8 -> v2.4.8.1
[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
35
36
37 #if defined(LINUX_2_1) || defined(LINUX_2_4) 
38  #include <linux/init.h>        /* __initfunc et al. */
39  #include <asm/uaccess.h>       /* copy_to_user */
40  #define PROC_STATS_FORMAT "%30s: %12lu\n"
41 #else
42  #define PROC_STATS_FORMAT "%30s: %12u\n"
43  #include <asm/segment.h>       /* kernel <-> user copy */
44 #endif
45
46
47 /****** Defines and Macros **************************************************/
48
49 #ifndef min
50 #define min(a,b) (((a)<(b))?(a):(b))
51 #endif
52 #ifndef max
53 #define max(a,b) (((a)>(b))?(a):(b))
54 #endif
55
56 #define PROC_BUFSZ      4000    /* buffer size for printing proc info */
57
58 #define PROT_DECODE(prot) ((prot == WANCONFIG_FR) ? " FR" :\
59                               (prot == WANCONFIG_X25) ? " X25" : \
60                                  (prot == WANCONFIG_PPP) ? " PPP" : \
61                                     (prot == WANCONFIG_CHDLC) ? " CHDLC": \
62                                        (prot == WANCONFIG_MPPP) ? " MPPP" : \
63                                            " Unknown" )
64         
65 /****** Data Types **********************************************************/
66
67 typedef struct wan_stat_entry
68 {
69         struct wan_stat_entry *next;
70         char *description;              /* description string */
71         void *data;                     /* -> data */
72         unsigned data_type;             /* data type */
73 } wan_stat_entry_t;
74
75 /****** Function Prototypes *************************************************/
76
77 #ifdef CONFIG_PROC_FS
78
79
80 #ifdef LINUX_2_4  /* Start of LINUX 2.4.X code */
81
82
83         /* Proc filesystem interface */
84         static int router_proc_perms(struct inode *, int);
85         static ssize_t router_proc_read(struct file* file, char* buf, size_t count,                                     loff_t *ppos);
86
87         /* Methods for preparing data for reading proc entries */
88
89         static int config_get_info(char* buf, char** start, off_t offs, int len);
90         static int status_get_info(char* buf, char** start, off_t offs, int len);
91         static int wandev_get_info(char* buf, char** start, off_t offs, int len);
92
93         /* Miscellaneous */
94
95         /*
96          *      Structures for interfacing with the /proc filesystem.
97          *      Router creates its own directory /proc/net/router with the folowing
98          *      entries:
99          *      config          device configuration
100          *      status          global device statistics
101          *      <device>        entry for each WAN device
102          */
103
104         /*
105          *      Generic /proc/net/router/<file> file and inode operations 
106          */
107         static struct file_operations router_fops =
108         {
109                 read:           router_proc_read,
110         };
111
112         static struct inode_operations router_inode =
113         {
114                 permission:     router_proc_perms,
115         };
116
117         /*
118          *      /proc/net/router/<device> file operations
119          */
120
121         static struct file_operations wandev_fops =
122         {
123                 read:           router_proc_read,
124                 ioctl:          wanrouter_ioctl,
125         };
126
127         /*
128          *      /proc/net/router 
129          */
130
131         static struct proc_dir_entry *proc_router;
132
133         /* Strings */
134         static char conf_hdr[] =
135                 "Device name    | port |IRQ|DMA|  mem.addr  |mem.size|"
136                 "option1|option2|option3|option4\n";
137                 
138         static char stat_hdr[] =
139                 "Device name    |protocol|station|interface|clocking|baud rate"
140                 "| MTU |ndev|link state\n";
141
142
143         /*
144          *      Interface functions
145          */
146
147         /*
148          *      Initialize router proc interface.
149          */
150
151         int __init wanrouter_proc_init (void)
152         {
153                 struct proc_dir_entry *p;
154                 proc_router = proc_mkdir(ROUTER_NAME, proc_net);
155                 if (!proc_router)
156                         goto fail;
157
158                 p = create_proc_entry("config",0,proc_router);
159                 if (!p)
160                         goto fail_config;
161                 p->proc_fops = &router_fops;
162                 p->proc_iops = &router_inode;
163                 p->get_info = config_get_info;
164                 p = create_proc_entry("status",0,proc_router);
165                 if (!p)
166                         goto fail_stat;
167                 p->proc_fops = &router_fops;
168                 p->proc_iops = &router_inode;
169                 p->get_info = status_get_info;
170                 return 0;
171         fail_stat:
172                 remove_proc_entry("config", proc_router);
173         fail_config:
174                 remove_proc_entry(ROUTER_NAME, proc_net);
175         fail:
176                 return -ENOMEM;
177         }
178
179         /*
180          *      Clean up router proc interface.
181          */
182
183         void wanrouter_proc_cleanup (void)
184         {
185                 remove_proc_entry("config", proc_router);
186                 remove_proc_entry("status", proc_router);
187                 remove_proc_entry(ROUTER_NAME,proc_net);
188         }
189
190         /*
191          *      Add directory entry for WAN device.
192          */
193
194         int wanrouter_proc_add (wan_device_t* wandev)
195         {
196                 if (wandev->magic != ROUTER_MAGIC)
197                         return -EINVAL;
198                         
199                 wandev->dent = create_proc_entry(wandev->name, 0, proc_router);
200                 if (!wandev->dent)
201                         return -ENOMEM;
202                 wandev->dent->proc_fops = &wandev_fops;
203                 wandev->dent->proc_iops = &router_inode;
204                 wandev->dent->get_info  = wandev_get_info;
205                 wandev->dent->data      = wandev;
206                 return 0;
207         }
208
209         /*
210          *      Delete directory entry for WAN device.
211          */
212          
213         int wanrouter_proc_delete(wan_device_t* wandev)
214         {
215                 if (wandev->magic != ROUTER_MAGIC)
216                         return -EINVAL;
217                 remove_proc_entry(wandev->name, proc_router);
218                 return 0;
219         }
220
221         /****** Proc filesystem entry points ****************************************/
222
223         /*
224          *      Verify access rights.
225          */
226
227         static int router_proc_perms (struct inode* inode, int op)
228         {
229                 return 0;
230         }
231
232         /*
233          *      Read router proc directory entry.
234          *      This is universal routine for reading all entries in /proc/net/wanrouter
235          *      directory.  Each directory entry contains a pointer to the 'method' for
236          *      preparing data for that entry.
237          *      o verify arguments
238          *      o allocate kernel buffer
239          *      o call get_info() to prepare data
240          *      o copy data to user space
241          *      o release kernel buffer
242          *
243          *      Return: number of bytes copied to user space (0, if no data)
244          *              <0      error
245          */
246
247         static ssize_t router_proc_read(struct file* file, char* buf, size_t count,
248                                         loff_t *ppos)
249         {
250                 struct inode *inode = file->f_dentry->d_inode;
251                 struct proc_dir_entry* dent;
252                 char* page;
253                 int pos, offs, len;
254
255                 if (count <= 0)
256                         return 0;
257                         
258                 dent = inode->u.generic_ip;
259                 if ((dent == NULL) || (dent->get_info == NULL))
260                         return 0;
261                         
262                 page = kmalloc(PROC_BUFSZ, GFP_KERNEL);
263                 if (page == NULL)
264                         return -ENOBUFS;
265                         
266                 pos = dent->get_info(page, dent->data, 0, 0);
267                 offs = file->f_pos;
268                 if (offs < pos) {
269                         len = min(pos - offs, count);
270                         if (copy_to_user(buf, (page + offs), len)) {
271                                 kfree(page);
272                                 return -EFAULT;
273                         }
274                         file->f_pos += len;
275                 }
276                 else
277                         len = 0;
278                 kfree(page);
279                 return len;
280         }
281
282         /*
283          *      Prepare data for reading 'Config' entry.
284          *      Return length of data.
285          */
286
287         static int config_get_info(char* buf, char** start, off_t offs, int len)
288         {
289                 int cnt = sizeof(conf_hdr) - 1;
290                 wan_device_t* wandev;
291                 strcpy(buf, conf_hdr);
292                 for (wandev = router_devlist;
293                      wandev && (cnt < (PROC_BUFSZ - 120));
294                      wandev = wandev->next) {
295                         if (wandev->state) cnt += sprintf(&buf[cnt],
296                                 "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n",
297                                 wandev->name,
298                                 wandev->ioport,
299                                 wandev->irq,
300                                 wandev->dma,
301                                 wandev->maddr,
302                                 wandev->msize,
303                                 wandev->hw_opt[0],
304                                 wandev->hw_opt[1],
305                                 wandev->hw_opt[2],
306                                 wandev->hw_opt[3]);
307                 }
308
309                 return cnt;
310         }
311
312         /*
313          *      Prepare data for reading 'Status' entry.
314          *      Return length of data.
315          */
316
317         static int status_get_info(char* buf, char** start, off_t offs, int len)
318         {
319                 int cnt = 0;
320                 wan_device_t* wandev;
321
322                 //cnt += sprintf(&buf[cnt], "\nSTATUS:\n\n");
323                 strcpy(&buf[cnt], stat_hdr);
324                 cnt += sizeof(stat_hdr) - 1;
325
326                 for (wandev = router_devlist;
327                      wandev && (cnt < (PROC_BUFSZ - 80));
328                      wandev = wandev->next) {
329                         if (!wandev->state) continue;
330                         cnt += sprintf(&buf[cnt],
331                                 "%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |",
332                                 wandev->name,
333                                 PROT_DECODE(wandev->config_id),
334                                 wandev->config_id == WANCONFIG_FR ? 
335                                         (wandev->station ? " Node" : " CPE") :
336                                         (wandev->config_id == WANCONFIG_X25 ?
337                                         (wandev->station ? " DCE" : " DTE") :
338                                         (" N/A")),
339                                 wandev->interface ? " V.35" : " RS-232",
340                                 wandev->clocking ? "internal" : "external",
341                                 wandev->bps,
342                                 wandev->mtu,
343                                 wandev->ndev);
344
345                         switch (wandev->state) {
346
347                         case WAN_UNCONFIGURED:
348                                 cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured");
349                                 break;
350
351                         case WAN_DISCONNECTED:
352                                 cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected");
353                                 break;
354
355                         case WAN_CONNECTING:
356                                 cnt += sprintf(&buf[cnt], "%-12s\n", "connecting");
357                                 break;
358
359                         case WAN_CONNECTED:
360                                 cnt += sprintf(&buf[cnt], "%-12s\n", "connected");
361                                 break;
362
363                         default:
364                                 cnt += sprintf(&buf[cnt], "%-12s\n", "invalid");
365                                 break;
366                         }
367                 }
368                 return cnt;
369         }
370
371         /*
372          *      Prepare data for reading <device> entry.
373          *      Return length of data.
374          *
375          *      On entry, the 'start' argument will contain a pointer to WAN device
376          *      data space.
377          */
378
379         static int wandev_get_info(char* buf, char** start, off_t offs, int len)
380         {
381                 wan_device_t* wandev = (void*)start;
382                 int cnt = 0;
383                 int rslt = 0;
384
385                 if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC))
386                         return 0;
387                 if (!wandev->state)
388                         return sprintf(&buf[cnt], "device is not configured!\n");
389
390                 /* Update device statistics */
391                 if (wandev->update) {
392
393                         rslt = wandev->update(wandev);
394                         if(rslt) {
395                                 switch (rslt) {
396                                 case -EAGAIN:
397                                         return sprintf(&buf[cnt], "Device is busy!\n");
398
399                                 default:
400                                         return sprintf(&buf[cnt],
401                                                 "Device is not configured!\n");
402                                 }
403                         }
404                 }
405
406                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
407                         "total packets received", wandev->stats.rx_packets);
408                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
409                         "total packets transmitted", wandev->stats.tx_packets);
410                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
411                         "total bytes received", wandev->stats.rx_bytes);
412                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
413                         "total bytes transmitted", wandev->stats.tx_bytes);
414                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
415                         "bad packets received", wandev->stats.rx_errors);
416                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
417                         "packet transmit problems", wandev->stats.tx_errors);
418                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
419                         "received frames dropped", wandev->stats.rx_dropped);
420                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
421                         "transmit frames dropped", wandev->stats.tx_dropped);
422                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
423                         "multicast packets received", wandev->stats.multicast);
424                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
425                         "transmit collisions", wandev->stats.collisions);
426                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
427                         "receive length errors", wandev->stats.rx_length_errors);
428                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
429                         "receiver overrun errors", wandev->stats.rx_over_errors);
430                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
431                         "CRC errors", wandev->stats.rx_crc_errors);
432                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
433                         "frame format errors (aborts)", wandev->stats.rx_frame_errors);
434                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
435                         "receiver fifo overrun", wandev->stats.rx_fifo_errors);
436                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
437                         "receiver missed packet", wandev->stats.rx_missed_errors);
438                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
439                         "aborted frames transmitted", wandev->stats.tx_aborted_errors);
440                 return cnt;
441         }
442
443
444 #else /* ------------------- END OF LINUX 2.4.X VERSION -------------*/
445
446
447
448         /* Proc filesystem interface */
449         static int router_proc_perms(struct inode *, int);
450 #ifdef LINUX_2_1
451         static ssize_t router_proc_read(struct file *file, char *buf, size_t count,                                     loff_t *ppos);
452 #else
453         static int router_proc_read(
454                 struct inode* inode, struct file* file, char* buf, int count);
455         static int device_write(
456                 struct inode* inode, struct file* file, const char* buf, int count);
457 #endif
458
459         /* Methods for preparing data for reading proc entries */
460         static int config_get_info(char* buf, char** start, off_t offs, int len,
461                 int dummy);
462         static int status_get_info(char* buf, char** start, off_t offs, int len,
463                 int dummy);
464         static int wandev_get_info(char* buf, char** start, off_t offs, int len,
465                 int dummy);
466
467         /* Miscellaneous */
468
469         /*
470          *      Global Data
471          */
472
473         /*
474          *      Names of the proc directory entries 
475          */
476
477         static char name_root[] = ROUTER_NAME;
478         static char name_conf[] = "config";
479         static char name_stat[] = "status";
480
481         /*
482          *      Structures for interfacing with the /proc filesystem.
483          *      Router creates its own directory /proc/net/router with the folowing
484          *      entries:
485          *      config          device configuration
486          *      status          global device statistics
487          *      <device>        entry for each WAN device
488          */
489
490         /*
491          *      Generic /proc/net/router/<file> file and inode operations 
492          */
493 #ifdef LINUX_2_1
494         static struct file_operations router_fops =
495         {
496                 NULL,                   /* lseek   */
497                 router_proc_read,       /* read    */
498                 NULL,                   /* write   */
499                 NULL,                   /* readdir */
500                 NULL,                   /* select  */
501                 NULL,                   /* ioctl   */
502                 NULL,                   /* mmap    */
503                 NULL,                   /* no special open code    */
504                 NULL,                   /* flush */
505                 NULL,                   /* no special release code */
506                 NULL                    /* can't fsync */
507         };
508 #else
509         static struct file_operations router_fops =
510         {
511                 NULL,                   /* lseek   */
512                 router_proc_read,       /* read    */
513                 NULL,                   /* write   */
514                 NULL,                   /* readdir */
515                 NULL,                   /* select  */
516                 NULL,                   /* ioctl   */
517                 NULL,                   /* mmap    */
518                 NULL,                   /* no special open code    */
519                 NULL,                   /* no special release code */
520                 NULL                    /* can't fsync */
521         };
522 #endif
523
524         static struct inode_operations router_inode =
525         {
526                 &router_fops,
527                 NULL,                   /* create */
528                 NULL,                   /* lookup */
529                 NULL,                   /* link */
530                 NULL,                   /* unlink */
531                 NULL,                   /* symlink */
532                 NULL,                   /* mkdir */
533                 NULL,                   /* rmdir */
534                 NULL,                   /* mknod */
535                 NULL,                   /* rename */
536                 NULL,                   /* follow link */
537                 NULL,                   /* readlink */
538                 NULL,                   /* readpage */
539                 NULL,                   /* writepage */
540                 NULL,                   /* bmap */
541                 NULL,                   /* truncate */
542                 router_proc_perms
543         };
544
545         /*
546          *      /proc/net/router/<device> file and inode operations
547          */
548
549 #ifdef LINUX_2_1
550         static struct file_operations wandev_fops =
551         {
552                 NULL,                   /* lseek   */
553                 router_proc_read,       /* read    */
554                 NULL,                   /* write   */
555                 NULL,                   /* readdir */
556                 NULL,                   /* select  */
557                 wanrouter_ioctl,        /* ioctl   */
558                 NULL,                   /* mmap    */
559                 NULL,                   /* no special open code    */
560                 NULL,                   /* flush */
561                 NULL,                   /* no special release code */
562                 NULL                    /* can't fsync */
563         };
564 #else
565         static struct file_operations wandev_fops =
566         {
567                 NULL,                   /* lseek   */
568                 router_proc_read,       /* read    */
569                 device_write,           /* write   */
570                 NULL,                   /* readdir */
571                 NULL,                   /* select  */
572                 wanrouter_ioctl,        /* ioctl   */
573                 NULL,                   /* mmap    */
574                 NULL,                   /* no special open code    */
575                 NULL,                   /* no special release code */
576                 NULL                    /* can't fsync */
577         };
578 #endif
579
580         static struct inode_operations wandev_inode =
581         {
582                 &wandev_fops,
583                 NULL,                   /* create */
584                 NULL,                   /* lookup */
585                 NULL,                   /* link */
586                 NULL,                   /* unlink */
587                 NULL,                   /* symlink */
588                 NULL,                   /* mkdir */
589                 NULL,                   /* rmdir */
590                 NULL,                   /* mknod */
591                 NULL,                   /* rename */
592                 NULL,                   /* readlink */
593                 NULL,                   /* follow_link */
594                 NULL,                   /* readpage */
595                 NULL,                   /* writepage */
596                 NULL,                   /* bmap */
597                 NULL,                   /* truncate */
598                 router_proc_perms
599         };
600
601         /*
602          * Proc filesystem derectory entries.
603          */
604
605         /*
606          *      /proc/net/router 
607          */
608          
609         static struct proc_dir_entry proc_router =
610         {
611                 0,                      /* .low_ino */
612                 sizeof(name_root) - 1,  /* .namelen */
613                 name_root,              /* .name */
614                 0555 | S_IFDIR,         /* .mode */
615                 2,                      /* .nlink */
616                 0,                      /* .uid */
617                 0,                      /* .gid */
618                 0,                      /* .size */
619                 &proc_dir_inode_operations, /* .ops */
620                 NULL,                   /* .get_info */
621                 NULL,                   /* .fill_node */
622                 NULL,                   /* .next */
623                 NULL,                   /* .parent */
624                 NULL,                   /* .subdir */
625                 NULL,                   /* .data */
626         };
627
628         /*
629          *      /proc/net/router/config 
630          */
631          
632         static struct proc_dir_entry proc_router_conf =
633         {
634                 0,                      /* .low_ino */
635                 sizeof(name_conf) - 1,  /* .namelen */
636                 name_conf,              /* .name */
637                 0444 | S_IFREG,         /* .mode */
638                 1,                      /* .nlink */
639                 0,                      /* .uid */
640                 0,                      /* .gid */
641                 0,                      /* .size */
642                 &router_inode,          /* .ops */
643                 &config_get_info,       /* .get_info */
644                 NULL,                   /* .fill_node */
645                 NULL,                   /* .next */
646                 NULL,                   /* .parent */
647                 NULL,                   /* .subdir */
648                 NULL,                   /* .data */
649         };
650
651         /*
652          *      /proc/net/router/status 
653          */
654          
655         static struct proc_dir_entry proc_router_stat =
656         {
657                 0,                      /* .low_ino */
658                 sizeof(name_stat) - 1,  /* .namelen */
659                 name_stat,              /* .name */
660                 0444 | S_IFREG,         /* .mode */
661                 1,                      /* .nlink */
662                 0,                      /* .uid */
663                 0,                      /* .gid */
664                 0,                      /* .size */
665                 &router_inode,          /* .ops */
666                 status_get_info,        /* .get_info */
667                 NULL,                   /* .fill_node */
668                 NULL,                   /* .next */
669                 NULL,                   /* .parent */
670                 NULL,                   /* .subdir */
671                 NULL,                   /* .data */
672         };
673
674         /* Strings */
675         static char conf_hdr[] =
676                 "Device name    | port |IRQ|DMA|  mem.addr  |mem.size|"
677                 "option1|option2|option3|option4\n";
678                 
679         static char stat_hdr[] =
680                 "Device name    |protocol|station|interface|clocking|baud rate| MTU |ndev"
681                 "|link state\n";
682
683
684         /*
685          *      Interface functions
686          */
687
688         /*
689          *      Initialize router proc interface.
690          */
691
692 #ifdef LINUX_2_1
693         __initfunc(int wanrouter_proc_init (void))
694         {
695                 int err = proc_register(proc_net, &proc_router);
696
697                 if (!err) {
698                         proc_register(&proc_router, &proc_router_conf);
699                         proc_register(&proc_router, &proc_router_stat);
700                 }
701                 return err;
702         }
703 #else
704         int wanrouter_proc_init (void)
705         {
706                 int err = proc_register_dynamic(&proc_net, &proc_router);
707
708                 if (!err) {
709                         proc_register_dynamic(&proc_router, &proc_router_conf);
710                         proc_register_dynamic(&proc_router, &proc_router_stat);
711                 }
712                 return err;
713         }
714 #endif
715
716         /*
717          *      Clean up router proc interface.
718          */
719
720         void wanrouter_proc_cleanup (void)
721         {
722                 proc_unregister(&proc_router, proc_router_conf.low_ino);
723                 proc_unregister(&proc_router, proc_router_stat.low_ino);
724 #ifdef LINUX_2_1
725                 proc_unregister(proc_net, proc_router.low_ino);
726 #else
727                 proc_unregister(&proc_net, proc_router.low_ino);
728 #endif
729         }
730
731         /*
732          *      Add directory entry for WAN device.
733          */
734
735         int wanrouter_proc_add (wan_device_t* wandev)
736         {
737                 if (wandev->magic != ROUTER_MAGIC)
738                         return -EINVAL;
739                 
740                 memset(&wandev->dent, 0, sizeof(wandev->dent));
741                 wandev->dent.namelen    = strlen(wandev->name);
742                 wandev->dent.name       = wandev->name;
743                 wandev->dent.mode       = 0444 | S_IFREG;
744                 wandev->dent.nlink      = 1;
745                 wandev->dent.ops        = &wandev_inode;
746                 wandev->dent.get_info   = &wandev_get_info;
747                 wandev->dent.data       = wandev;
748 #ifdef LINUX_2_1
749                 return proc_register(&proc_router, &wandev->dent);
750 #else
751                 return proc_register_dynamic(&proc_router, &wandev->dent);
752 #endif
753         }
754
755         /*
756          *      Delete directory entry for WAN device.
757          */
758          
759         int wanrouter_proc_delete(wan_device_t* wandev)
760         {
761                 if (wandev->magic != ROUTER_MAGIC)
762                         return -EINVAL;
763                 proc_unregister(&proc_router, wandev->dent.low_ino);
764                 return 0;
765         }
766
767         /****** Proc filesystem entry points ****************************************/
768
769         /*
770          *      Verify access rights.
771          */
772
773         static int router_proc_perms (struct inode* inode, int op)
774         {
775                 return 0;
776         }
777
778         /*
779          *      Read router proc directory entry.
780          *      This is universal routine for reading all entries in /proc/net/wanrouter
781          *      directory.  Each directory entry contains a pointer to the 'method' for
782          *      preparing data for that entry.
783          *      o verify arguments
784          *      o allocate kernel buffer
785          *      o call get_info() to prepare data
786          *      o copy data to user space
787          *      o release kernel buffer
788          *
789          *      Return: number of bytes copied to user space (0, if no data)
790          *              <0      error
791          */
792 #ifdef LINUX_2_1
793         static ssize_t router_proc_read(struct file* file, char* buf, size_t count,
794                                         loff_t *ppos)
795         {
796                 struct inode *inode = file->f_dentry->d_inode;
797                 struct proc_dir_entry* dent;
798                 char* page;
799                 int pos, offs, len;
800
801                 if (count <= 0)
802                         return 0;
803                         
804                 dent = inode->u.generic_ip;
805                 if ((dent == NULL) || (dent->get_info == NULL))
806                         return 0;
807                         
808                 page = kmalloc(PROC_BUFSZ, GFP_KERNEL);
809                 if (page == NULL)
810                         return -ENOBUFS;
811                         
812                 pos = dent->get_info(page, dent->data, 0, 0, 0);
813                 offs = file->f_pos;
814                 if (offs < pos) {
815                         len = min(pos - offs, count);
816                         if (copy_to_user(buf, (page + offs), len)) {
817                                 kfree(page);
818                                 return -EFAULT;
819                         }
820                         file->f_pos += len;
821                 }
822                 else
823                         len = 0;
824                 kfree(page);
825                 return len;
826         }
827
828 #else
829         static int router_proc_read(
830                 struct inode* inode, struct file* file, char* buf, int count)
831         {
832                 struct proc_dir_entry* dent;
833                 char* page;
834                 int err, pos, offs, len;
835
836                 if (count <= 0)
837                         return 0;
838                 dent = inode->u.generic_ip;
839                 if ((dent == NULL) || (dent->get_info == NULL))
840                         return -ENODATA;
841                 err = verify_area(VERIFY_WRITE, buf, count);
842                 if (err) return err;
843
844                 page = kmalloc(PROC_BUFSZ, GFP_KERNEL);
845                 if (page == NULL)
846                         return -ENOMEM;
847
848                 pos = dent->get_info(page, dent->data, 0, 0, 0);
849                 offs = file->f_pos;
850                 if (offs < pos) {
851                         len = min(pos - offs, count);
852                         memcpy_tofs((void*)buf, (void*)(page + offs), len);
853                         file->f_pos += len;
854                 }
855                 else len = 0;
856                 kfree(page);
857                 return len;
858         }
859 #endif
860
861
862         /*
863          *      Prepare data for reading 'Config' entry.
864          *      Return length of data.
865          */
866
867         static int config_get_info(char* buf, char** start, off_t offs, int len, 
868                 int dummy)
869         {
870                 int cnt = sizeof(conf_hdr) - 1;
871                 wan_device_t* wandev;
872                 strcpy(buf, conf_hdr);
873                 for (wandev = router_devlist;
874                      wandev && (cnt < (PROC_BUFSZ - 120));
875                      wandev = wandev->next) {
876                         if (wandev->state) cnt += sprintf(&buf[cnt],
877                                 "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n",
878                                 wandev->name,
879                                 wandev->ioport,
880                                 wandev->irq,
881                                 wandev->dma,
882                                 wandev->maddr,
883                                 wandev->msize,
884                                 wandev->hw_opt[0],
885                                 wandev->hw_opt[1],
886                                 wandev->hw_opt[2],
887                                 wandev->hw_opt[3]);
888                 }
889
890                 return cnt;
891         }
892
893         /*
894          *      Prepare data for reading 'Status' entry.
895          *      Return length of data.
896          */
897
898         static int status_get_info(char* buf, char** start, off_t offs, int len, 
899                                 int dummy)
900         {
901                 int cnt = 0;
902                 wan_device_t* wandev;
903
904                 //cnt += sprintf(&buf[cnt], "\nSTATUS:\n\n");
905                 strcpy(&buf[cnt], stat_hdr);
906                 cnt += sizeof(stat_hdr) - 1;
907
908                 for (wandev = router_devlist;
909                      wandev && (cnt < (PROC_BUFSZ - 80));
910                      wandev = wandev->next) {
911                         if (!wandev->state) continue;
912                         cnt += sprintf(&buf[cnt],
913                                 "%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |",
914                                 wandev->name,
915                                 PROT_DECODE(wandev->config_id),
916                                 wandev->config_id == WANCONFIG_FR ? 
917                                         (wandev->station ? " Node" : " CPE") :
918                                         (wandev->config_id == WANCONFIG_X25 ?
919                                         (wandev->station ? " DCE" : " DTE") :
920                                         (" N/A")),
921                                 wandev->interface ? " V.35" : " RS-232",
922                                 wandev->clocking ? "internal" : "external",
923                                 wandev->bps,
924                                 wandev->mtu,
925                                 wandev->ndev);
926
927                         switch (wandev->state) {
928
929                         case WAN_UNCONFIGURED:
930                                 cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured");
931                                 break;
932
933                         case WAN_DISCONNECTED:
934                                 cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected");
935                                 break;
936
937                         case WAN_CONNECTING:
938                                 cnt += sprintf(&buf[cnt], "%-12s\n", "connecting");
939                                 break;
940
941                         case WAN_CONNECTED:
942                                 cnt += sprintf(&buf[cnt], "%-12s\n", "connected");
943                                 break;
944
945                         case WAN_FT1_READY:
946                                 cnt += sprintf(&buf[cnt], "%-12s\n", "ft1 ready");
947                                 break;
948
949                         default:
950                                 cnt += sprintf(&buf[cnt], "%-12s\n", "invalid");
951                                 break;
952                         }
953                 }
954                 return cnt;
955         }
956
957         /*
958          *      Prepare data for reading <device> entry.
959          *      Return length of data.
960          *
961          *      On entry, the 'start' argument will contain a pointer to WAN device
962          *      data space.
963          */
964
965         static int wandev_get_info(char* buf, char** start, off_t offs, int len, 
966                                 int dummy)
967         {
968                 wan_device_t* wandev = (void*)start;
969                 int cnt = 0;
970                 int rslt = 0;
971
972                 if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC))
973                         return 0;
974                 if (!wandev->state)
975                         return sprintf(&buf[cnt], "Device is not configured!\n");
976
977                 /* Update device statistics */
978                 if (wandev->update) {
979
980                         rslt = wandev->update(wandev);
981                         if(rslt) {
982                                 switch (rslt) {
983                                 case -EAGAIN:
984                                         return sprintf(&buf[cnt], "Device is busy!\n");
985
986                                 default:
987                                         return sprintf(&buf[cnt],
988                                                 "Device is not configured!\n");
989                                 }
990                         }
991                 }
992
993                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
994                         "total packets received", wandev->stats.rx_packets);
995                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
996                         "total packets transmitted", wandev->stats.tx_packets);
997 #ifdef LINUX_2_1
998                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
999                         "total bytes received", wandev->stats.rx_bytes);
1000                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
1001                         "total bytes transmitted", wandev->stats.tx_bytes);
1002 #endif
1003                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
1004                         "bad packets received", wandev->stats.rx_errors);
1005                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
1006                         "packet transmit problems", wandev->stats.tx_errors);
1007                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
1008                         "received frames dropped", wandev->stats.rx_dropped);
1009                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
1010                         "transmit frames dropped", wandev->stats.tx_dropped);
1011                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
1012                         "multicast packets received", wandev->stats.multicast);
1013                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
1014                         "transmit collisions", wandev->stats.collisions);
1015                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
1016                         "receive length errors", wandev->stats.rx_length_errors);
1017                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
1018                         "receiver overrun errors", wandev->stats.rx_over_errors);
1019                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
1020                         "CRC errors", wandev->stats.rx_crc_errors);
1021                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
1022                         "frame format errors (aborts)", wandev->stats.rx_frame_errors);
1023                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
1024                         "receiver fifo overrun", wandev->stats.rx_fifo_errors);
1025                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
1026                         "receiver missed packet", wandev->stats.rx_missed_errors);
1027                 cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
1028                         "aborted frames transmitted", wandev->stats.tx_aborted_errors);
1029
1030                 return cnt;
1031         }
1032
1033 #endif /* End of ifdef LINUX_2_4 */
1034
1035
1036 #else
1037
1038 /*
1039  *      No /proc - output stubs
1040  */
1041
1042 int __init wanrouter_proc_init(void)
1043 {
1044         return 0;
1045 }
1046
1047 void wanrouter_proc_cleanup(void)
1048 {
1049         return;
1050 }
1051
1052 int wanrouter_proc_add(wan_device_t *wandev)
1053 {
1054         return 0;
1055 }
1056
1057 int wanrouter_proc_delete(wan_device_t *wandev)
1058 {
1059         return 0;
1060 }
1061
1062 #endif
1063
1064 /*============================================================================
1065  * Write WAN device ???.
1066  * o Find WAN device associated with this node
1067  */
1068 #ifdef LINUX_2_0
1069 static int device_write(
1070         struct inode* inode, struct file* file, const char* buf, int count)
1071 {
1072         int err = verify_area(VERIFY_READ, buf, count);
1073         struct proc_dir_entry* dent;
1074         wan_device_t* wandev;
1075
1076         if (err) return err;
1077
1078         dent = inode->u.generic_ip;
1079         if ((dent == NULL) || (dent->data == NULL))
1080                 return -ENODATA;
1081
1082         wandev = dent->data;
1083
1084         printk(KERN_ERR "%s: writing %d bytes to %s...\n",
1085                 name_root, count, dent->name);
1086         
1087         return 0;
1088 }
1089 #endif
1090
1091 /*
1092  *      End
1093  */
1094