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