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