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
60typedef 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
1035int __init wanrouter_proc_init(void)
1036{
1037	return 0;
1038}
1039
1040void wanrouter_proc_cleanup(void)
1041{
1042	return;
1043}
1044
1045int wanrouter_proc_add(wan_device_t *wandev)
1046{
1047	return 0;
1048}
1049
1050int 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
1062static 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
1088