patch-2.4.4 linux/net/wanrouter/wanproc.c

Next file: linux/net/x25/af_x25.c
Previous file: linux/net/wanrouter/wanmain.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.3/linux/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c
@@ -13,7 +13,6 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
-* Jan 20, 2001  Arnaldo C.Melo  Fix leak on error in router_proc_read, cleanups
 * Jun 02, 1999  Gideon Hack	Updates for Linux 2.2.X kernels.
 * Jun 29, 1997	Alan Cox	Merged with 1.0.3 vendor code
 * Jan 29, 1997	Gene Kozin	v1.0.1. Implemented /proc read routines
@@ -26,397 +25,1017 @@
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/kernel.h>
-#include <linux/slab.h>	/* kmalloc(), kfree() */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
 #include <linux/mm.h>		/* verify_area(), etc. */
 #include <linux/string.h>	/* inline mem*, str* functions */
-#include <linux/init.h>		/* __init et al. */
-#include <asm/segment.h>	/* kernel <-> user copy */
 #include <asm/byteorder.h>	/* htons(), etc. */
-#include <asm/uaccess.h>	/* copy_to_user */
 #include <asm/io.h>
 #include <linux/wanrouter.h>	/* WAN router API definitions */
 
 
-/****** Defines and Macros **************************************************/
 
-#define PROC_STATS_FORMAT "%30s: %12lu\n"
+#if defined(LINUX_2_1) || defined(LINUX_2_4) 
+ #include <linux/init.h>	/* __initfunc et al. */
+ #include <asm/uaccess.h>       /* copy_to_user */
+ #define PROC_STATS_FORMAT "%30s: %12lu\n"
+#else
+ #define PROC_STATS_FORMAT "%30s: %12u\n"
+ #include <asm/segment.h>	/* kernel <-> user copy */
+#endif
+
+
+/****** Defines and Macros **************************************************/
 
 #ifndef	min
 #define min(a,b) (((a)<(b))?(a):(b))
 #endif
+#ifndef	max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
 
 #define	PROC_BUFSZ	4000	/* buffer size for printing proc info */
 
+#define PROT_DECODE(prot) ((prot == WANCONFIG_FR) ? " FR" :\
+			      (prot == WANCONFIG_X25) ? " X25" : \
+			         (prot == WANCONFIG_PPP) ? " PPP" : \
+				    (prot == WANCONFIG_CHDLC) ? " CHDLC": \
+				       (prot == WANCONFIG_MPPP) ? " MPPP" : \
+				           " Unknown" )
+	
+/****** Data Types **********************************************************/
+
+typedef struct wan_stat_entry
+{
+	struct wan_stat_entry *next;
+	char *description;		/* description string */
+	void *data;			/* -> data */
+	unsigned data_type;		/* data type */
+} wan_stat_entry_t;
+
 /****** Function Prototypes *************************************************/
 
 #ifdef CONFIG_PROC_FS
 
-/* Proc filesystem interface */
-static int router_proc_perms(struct inode *, int);
-static ssize_t router_proc_read(struct file* file, char* buf, size_t count, 					loff_t *ppos);
 
-/* Methods for preparing data for reading proc entries */
+#ifdef LINUX_2_4  /* Start of LINUX 2.4.X code */
 
-static int config_get_info(char* buf, char** start, off_t offs, int len);
-static int status_get_info(char* buf, char** start, off_t offs, int len);
-static int wandev_get_info(char* buf, char** start, off_t offs, int len);
 
-/* Miscellaneous */
+	/* Proc filesystem interface */
+	static int router_proc_perms(struct inode *, int);
+	static ssize_t router_proc_read(struct file* file, char* buf, size_t count, 					loff_t *ppos);
+
+	/* Methods for preparing data for reading proc entries */
+
+	static int config_get_info(char* buf, char** start, off_t offs, int len);
+	static int status_get_info(char* buf, char** start, off_t offs, int len);
+	static int wandev_get_info(char* buf, char** start, off_t offs, int len);
+
+	/* Miscellaneous */
+
+	/*
+	 *	Structures for interfacing with the /proc filesystem.
+	 *	Router creates its own directory /proc/net/router with the folowing
+	 *	entries:
+	 *	config		device configuration
+	 *	status		global device statistics
+	 *	<device>	entry for each WAN device
+	 */
+
+	/*
+	 *	Generic /proc/net/router/<file> file and inode operations 
+	 */
+	static struct file_operations router_fops =
+	{
+		read:		router_proc_read,
+	};
+
+	static struct inode_operations router_inode =
+	{
+		permission:	router_proc_perms,
+	};
+
+	/*
+	 *	/proc/net/router/<device> file operations
+	 */
+
+	static struct file_operations wandev_fops =
+	{
+		read:		router_proc_read,
+		ioctl:		wanrouter_ioctl,
+	};
+
+	/*
+	 *	/proc/net/router 
+	 */
+
+	static struct proc_dir_entry *proc_router;
+
+	/* Strings */
+	static char conf_hdr[] =
+		"Device name    | port |IRQ|DMA|  mem.addr  |mem.size|"
+		"option1|option2|option3|option4\n";
+		
+	static char stat_hdr[] =
+		"Device name    |protocol|station|interface|clocking|baud rate"
+		"| MTU |ndev|link state\n";
+
+
+	/*
+	 *	Interface functions
+	 */
+
+	/*
+	 *	Initialize router proc interface.
+	 */
+
+	int __init wanrouter_proc_init (void)
+	{
+		struct proc_dir_entry *p;
+		proc_router = proc_mkdir(ROUTER_NAME, proc_net);
+		if (!proc_router)
+			goto fail;
+
+		p = create_proc_entry("config",0,proc_router);
+		if (!p)
+			goto fail_config;
+		p->proc_fops = &router_fops;
+		p->proc_iops = &router_inode;
+		p->get_info = config_get_info;
+		p = create_proc_entry("status",0,proc_router);
+		if (!p)
+			goto fail_stat;
+		p->proc_fops = &router_fops;
+		p->proc_iops = &router_inode;
+		p->get_info = status_get_info;
+		return 0;
+	fail_stat:
+		remove_proc_entry("config", proc_router);
+	fail_config:
+		remove_proc_entry(ROUTER_NAME, proc_net);
+	fail:
+		return -ENOMEM;
+	}
 
-/*
- *	Structures for interfacing with the /proc filesystem.
- *	Router creates its own directory /proc/net/wanrouter with the folowing
- *	entries:
- *	config		device configuration
- *	status		global device statistics
- *	<device>	entry for each WAN device
- */
+	/*
+	 *	Clean up router proc interface.
+	 */
+
+	void wanrouter_proc_cleanup (void)
+	{
+		remove_proc_entry("config", proc_router);
+		remove_proc_entry("status", proc_router);
+		remove_proc_entry(ROUTER_NAME,proc_net);
+	}
 
-/*
- *	Generic /proc/net/wanrouter/<file> file and inode operations 
- */
-static struct file_operations router_fops =
-{
-	read:		router_proc_read,
-};
+	/*
+	 *	Add directory entry for WAN device.
+	 */
+
+	int wanrouter_proc_add (wan_device_t* wandev)
+	{
+		if (wandev->magic != ROUTER_MAGIC)
+			return -EINVAL;
+			
+		wandev->dent = create_proc_entry(wandev->name, 0, proc_router);
+		if (!wandev->dent)
+			return -ENOMEM;
+		wandev->dent->proc_fops	= &wandev_fops;
+		wandev->dent->proc_iops	= &router_inode;
+		wandev->dent->get_info	= wandev_get_info;
+		wandev->dent->data	= wandev;
+		return 0;
+	}
 
-static struct inode_operations router_inode =
-{
-	permission:	router_proc_perms,
-};
+	/*
+	 *	Delete directory entry for WAN device.
+	 */
+	 
+	int wanrouter_proc_delete(wan_device_t* wandev)
+	{
+		if (wandev->magic != ROUTER_MAGIC)
+			return -EINVAL;
+		remove_proc_entry(wandev->name, proc_router);
+		return 0;
+	}
 
-/*
- *	/proc/net/wanrouter/<device> file operations
- */
+	/****** Proc filesystem entry points ****************************************/
 
-static struct file_operations wandev_fops =
-{
-	read:		router_proc_read,
-	ioctl:		wanrouter_ioctl,
-};
+	/*
+	 *	Verify access rights.
+	 */
 
-/*
- *	/proc/net/wanrouter 
- */
+	static int router_proc_perms (struct inode* inode, int op)
+	{
+		return 0;
+	}
 
-static struct proc_dir_entry *proc_router;
+	/*
+	 *	Read router proc directory entry.
+	 *	This is universal routine for reading all entries in /proc/net/wanrouter
+	 *	directory.  Each directory entry contains a pointer to the 'method' for
+	 *	preparing data for that entry.
+	 *	o verify arguments
+	 *	o allocate kernel buffer
+	 *	o call get_info() to prepare data
+	 *	o copy data to user space
+	 *	o release kernel buffer
+	 *
+	 *	Return:	number of bytes copied to user space (0, if no data)
+	 *		<0	error
+	 */
+
+	static ssize_t router_proc_read(struct file* file, char* buf, size_t count,
+					loff_t *ppos)
+	{
+		struct inode *inode = file->f_dentry->d_inode;
+		struct proc_dir_entry* dent;
+		char* page;
+		int pos, offs, len;
+
+		if (count <= 0)
+			return 0;
+			
+		dent = inode->u.generic_ip;
+		if ((dent == NULL) || (dent->get_info == NULL))
+			return 0;
+			
+		page = kmalloc(PROC_BUFSZ, GFP_KERNEL);
+		if (page == NULL)
+			return -ENOBUFS;
+			
+		pos = dent->get_info(page, dent->data, 0, 0);
+		offs = file->f_pos;
+		if (offs < pos) {
+			len = min(pos - offs, count);
+			if(copy_to_user(buf, (page + offs), len))
+				return -EFAULT;
+			file->f_pos += len;
+		}
+		else
+			len = 0;
+		kfree(page);
+		return len;
+	}
 
-/* Strings */
-static char conf_hdr[] =
-	"Device name    | port |IRQ|DMA| mem.addr |mem.size|"
-	"option1|option2|option3|option4\n";
-	
-static char stat_hdr[] =
-	"Device name    |station|interface|clocking|baud rate| MTU |ndev"
-	"|link state\n";
+	/*
+	 *	Prepare data for reading 'Config' entry.
+	 *	Return length of data.
+	 */
+
+	static int config_get_info(char* buf, char** start, off_t offs, int len)
+	{
+		int cnt = sizeof(conf_hdr) - 1;
+		wan_device_t* wandev;
+		strcpy(buf, conf_hdr);
+		for (wandev = router_devlist;
+		     wandev && (cnt < (PROC_BUFSZ - 120));
+		     wandev = wandev->next) {
+			if (wandev->state) cnt += sprintf(&buf[cnt],
+				"%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n",
+				wandev->name,
+				wandev->ioport,
+				wandev->irq,
+				wandev->dma,
+				wandev->maddr,
+				wandev->msize,
+				wandev->hw_opt[0],
+				wandev->hw_opt[1],
+				wandev->hw_opt[2],
+				wandev->hw_opt[3]);
+		}
 
+		return cnt;
+	}
 
-/*
- *	Interface functions
- */
+	/*
+	 *	Prepare data for reading 'Status' entry.
+	 *	Return length of data.
+	 */
+
+	static int status_get_info(char* buf, char** start, off_t offs, int len)
+	{
+		int cnt = 0;
+		wan_device_t* wandev;
+
+		//cnt += sprintf(&buf[cnt], "\nSTATUS:\n\n");
+		strcpy(&buf[cnt], stat_hdr);
+		cnt += sizeof(stat_hdr) - 1;
+
+		for (wandev = router_devlist;
+		     wandev && (cnt < (PROC_BUFSZ - 80));
+		     wandev = wandev->next) {
+			if (!wandev->state) continue;
+			cnt += sprintf(&buf[cnt],
+				"%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |",
+				wandev->name,
+				PROT_DECODE(wandev->config_id),
+				wandev->config_id == WANCONFIG_FR ? 
+					(wandev->station ? " Node" : " CPE") :
+					(wandev->config_id == WANCONFIG_X25 ?
+					(wandev->station ? " DCE" : " DTE") :
+					(" N/A")),
+				wandev->interface ? " V.35" : " RS-232",
+				wandev->clocking ? "internal" : "external",
+				wandev->bps,
+				wandev->mtu,
+				wandev->ndev);
+
+			switch (wandev->state) {
+
+			case WAN_UNCONFIGURED:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured");
+				break;
+
+			case WAN_DISCONNECTED:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected");
+				break;
+
+			case WAN_CONNECTING:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "connecting");
+				break;
+
+			case WAN_CONNECTED:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "connected");
+				break;
 
-/*
- *	Initialize router proc interface.
- */
+			default:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "invalid");
+				break;
+			}
+		}
+		return cnt;
+	}
 
-int __init wanrouter_proc_init (void)
-{
-	struct proc_dir_entry *p;
-	proc_router = proc_mkdir(ROUTER_NAME, proc_net);
-	if (!proc_router)
-		goto fail;
-
-	p = create_proc_entry("config",0,proc_router);
-	if (!p)
-		goto fail_config;
-	p->proc_fops = &router_fops;
-	p->proc_iops = &router_inode;
-	p->get_info = config_get_info;
-	p = create_proc_entry("status",0,proc_router);
-	if (!p)
-		goto fail_stat;
-	p->proc_fops = &router_fops;
-	p->proc_iops = &router_inode;
-	p->get_info = status_get_info;
-	return 0;
-fail_stat:
-	remove_proc_entry("config", proc_router);
-fail_config:
-	remove_proc_entry(ROUTER_NAME, proc_net);
-fail:
-	return -ENOMEM;
-}
+	/*
+	 *	Prepare data for reading <device> entry.
+	 *	Return length of data.
+	 *
+	 *	On entry, the 'start' argument will contain a pointer to WAN device
+	 *	data space.
+	 */
+
+	static int wandev_get_info(char* buf, char** start, off_t offs, int len)
+	{
+		wan_device_t* wandev = (void*)start;
+		int cnt = 0;
+		int rslt = 0;
+
+		if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC))
+			return 0;
+		if (!wandev->state)
+			return sprintf(&buf[cnt], "device is not configured!\n");
+
+		/* Update device statistics */
+		if (wandev->update) {
+
+			rslt = wandev->update(wandev);
+			if(rslt) {
+				switch (rslt) {
+				case -EAGAIN:
+					return sprintf(&buf[cnt], "Device is busy!\n");
+
+				default:
+					return sprintf(&buf[cnt],
+						"Device is not configured!\n");
+				}
+			}
+		}
 
-/*
- *	Clean up router proc interface.
- */
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total packets received", wandev->stats.rx_packets);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total packets transmitted", wandev->stats.tx_packets);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total bytes received", wandev->stats.rx_bytes);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total bytes transmitted", wandev->stats.tx_bytes);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"bad packets received", wandev->stats.rx_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"packet transmit problems", wandev->stats.tx_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"received frames dropped", wandev->stats.rx_dropped);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"transmit frames dropped", wandev->stats.tx_dropped);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"multicast packets received", wandev->stats.multicast);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"transmit collisions", wandev->stats.collisions);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receive length errors", wandev->stats.rx_length_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receiver overrun errors", wandev->stats.rx_over_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"CRC errors", wandev->stats.rx_crc_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"frame format errors (aborts)", wandev->stats.rx_frame_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receiver fifo overrun", wandev->stats.rx_fifo_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receiver missed packet", wandev->stats.rx_missed_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"aborted frames transmitted", wandev->stats.tx_aborted_errors);
+		return cnt;
+	}
 
-void wanrouter_proc_cleanup (void)
-{
-	remove_proc_entry("config", proc_router);
-	remove_proc_entry("status", proc_router);
-	remove_proc_entry(ROUTER_NAME,proc_net);
-}
 
-/*
- *	Add directory entry for WAN device.
- */
+#else /* ------------------- END OF LINUX 2.4.X VERSION -------------*/
 
-int wanrouter_proc_add (wan_device_t* wandev)
-{
-	if (wandev->magic != ROUTER_MAGIC)
-		return -EINVAL;
-		
-	wandev->dent = create_proc_entry(wandev->name, 0, proc_router);
-	if (!wandev->dent)
-		return -ENOMEM;
-	wandev->dent->proc_fops	= &wandev_fops;
-	wandev->dent->proc_iops	= &router_inode;
-	wandev->dent->get_info	= wandev_get_info;
-	wandev->dent->data	= wandev;
-	return 0;
-}
 
-/*
- *	Delete directory entry for WAN device.
- */
- 
-int wanrouter_proc_delete(wan_device_t* wandev)
-{
-	if (wandev->magic != ROUTER_MAGIC)
-		return -EINVAL;
-	remove_proc_entry(wandev->name, proc_router);
-	return 0;
-}
 
-/****** Proc filesystem entry points ****************************************/
+	/* Proc filesystem interface */
+	static int router_proc_perms(struct inode *, int);
+#ifdef LINUX_2_1
+	static ssize_t router_proc_read(struct file *file, char *buf, size_t count, 					loff_t *ppos);
+#else
+	static int router_proc_read(
+		struct inode* inode, struct file* file, char* buf, int count);
+	static int device_write(
+		struct inode* inode, struct file* file, const char* buf, int count);
+#endif
 
-/*
- *	Verify access rights.
- */
+	/* Methods for preparing data for reading proc entries */
+	static int config_get_info(char* buf, char** start, off_t offs, int len,
+		int dummy);
+	static int status_get_info(char* buf, char** start, off_t offs, int len,
+		int dummy);
+	static int wandev_get_info(char* buf, char** start, off_t offs, int len,
+		int dummy);
+
+	/* Miscellaneous */
+
+	/*
+	 *	Global Data
+	 */
+
+	/*
+	 *	Names of the proc directory entries 
+	 */
+
+	static char name_root[]	= ROUTER_NAME;
+	static char name_conf[]	= "config";
+	static char name_stat[]	= "status";
+
+	/*
+	 *	Structures for interfacing with the /proc filesystem.
+	 *	Router creates its own directory /proc/net/router with the folowing
+	 *	entries:
+	 *	config		device configuration
+	 *	status		global device statistics
+	 *	<device>	entry for each WAN device
+	 */
+
+	/*
+	 *	Generic /proc/net/router/<file> file and inode operations 
+	 */
+#ifdef LINUX_2_1
+	static struct file_operations router_fops =
+	{
+		NULL,			/* lseek   */
+		router_proc_read,	/* read	   */
+		NULL,			/* write   */
+		NULL,			/* readdir */
+		NULL,			/* select  */
+		NULL,			/* ioctl   */
+		NULL,			/* mmap	   */
+		NULL,			/* no special open code	   */
+		NULL,			/* flush */
+		NULL,			/* no special release code */
+		NULL			/* can't fsync */
+	};
+#else
+	static struct file_operations router_fops =
+	{
+		NULL,                   /* lseek   */
+		router_proc_read,       /* read    */
+		NULL,                   /* write   */
+		NULL,                   /* readdir */
+		NULL,                   /* select  */
+		NULL,                   /* ioctl   */
+		NULL,                   /* mmap    */
+		NULL,                   /* no special open code    */
+		NULL,                   /* no special release code */
+		NULL                    /* can't fsync */
+	};
+#endif
 
-static int router_proc_perms (struct inode* inode, int op)
-{
-	return 0;
-}
+	static struct inode_operations router_inode =
+	{
+		&router_fops,
+		NULL,			/* create */
+		NULL,			/* lookup */
+		NULL,			/* link */
+		NULL,			/* unlink */
+		NULL,			/* symlink */
+		NULL,			/* mkdir */
+		NULL,			/* rmdir */
+		NULL,			/* mknod */
+		NULL,			/* rename */
+		NULL,			/* follow link */
+		NULL,			/* readlink */
+		NULL,			/* readpage */
+		NULL,			/* writepage */
+		NULL,			/* bmap */
+		NULL,			/* truncate */
+		router_proc_perms
+	};
+
+	/*
+	 *	/proc/net/router/<device> file and inode operations
+	 */
+
+#ifdef LINUX_2_1
+	static struct file_operations wandev_fops =
+	{
+		NULL,			/* lseek   */
+		router_proc_read,	/* read	   */
+		NULL,			/* write   */
+		NULL,			/* readdir */
+		NULL,			/* select  */
+		wanrouter_ioctl,	/* ioctl   */
+		NULL,			/* mmap	   */
+		NULL,			/* no special open code	   */
+		NULL,			/* flush */
+		NULL,			/* no special release code */
+		NULL			/* can't fsync */
+	};
+#else
+	static struct file_operations wandev_fops =
+	{
+		NULL,                   /* lseek   */
+		router_proc_read,       /* read    */
+		device_write,           /* write   */
+		NULL,                   /* readdir */
+		NULL,                   /* select  */
+		wanrouter_ioctl,        /* ioctl   */
+		NULL,                   /* mmap    */
+		NULL,                   /* no special open code    */
+		NULL,                   /* no special release code */
+		NULL                    /* can't fsync */
+	};
+#endif
 
-/*
- *	Read router proc directory entry.
- *	This is universal routine for reading all entries in /proc/net/wanrouter
- *	directory.  Each directory entry contains a pointer to the 'method' for
- *	preparing data for that entry.
- *	o verify arguments
- *	o allocate kernel buffer
- *	o call get_info() to prepare data
- *	o copy data to user space
- *	o release kernel buffer
- *
- *	Return:	number of bytes copied to user space (0, if no data)
- *		<0	error
- */
+	static struct inode_operations wandev_inode =
+	{
+		&wandev_fops,
+		NULL,			/* create */
+		NULL,			/* lookup */
+		NULL,			/* link */
+		NULL,			/* unlink */
+		NULL,			/* symlink */
+		NULL,			/* mkdir */
+		NULL,			/* rmdir */
+		NULL,			/* mknod */
+		NULL,			/* rename */
+		NULL,			/* readlink */
+		NULL,			/* follow_link */
+		NULL,			/* readpage */
+		NULL,			/* writepage */
+		NULL,			/* bmap */
+		NULL,			/* truncate */
+		router_proc_perms
+	};
+
+	/*
+	 * Proc filesystem derectory entries.
+	 */
+
+	/*
+	 *	/proc/net/router 
+	 */
+	 
+	static struct proc_dir_entry proc_router =
+	{
+		0,			/* .low_ino */
+		sizeof(name_root) - 1,	/* .namelen */
+		name_root,		/* .name */
+		0555 | S_IFDIR,		/* .mode */
+		2,			/* .nlink */
+		0,			/* .uid */
+		0,			/* .gid */
+		0,			/* .size */
+		&proc_dir_inode_operations, /* .ops */
+		NULL,			/* .get_info */
+		NULL,			/* .fill_node */
+		NULL,			/* .next */
+		NULL,			/* .parent */
+		NULL,			/* .subdir */
+		NULL,			/* .data */
+	};
+
+	/*
+	 *	/proc/net/router/config 
+	 */
+	 
+	static struct proc_dir_entry proc_router_conf =
+	{
+		0,			/* .low_ino */
+		sizeof(name_conf) - 1,	/* .namelen */
+		name_conf,		/* .name */
+		0444 | S_IFREG,		/* .mode */
+		1,			/* .nlink */
+		0,			/* .uid */
+		0,			/* .gid */
+		0,			/* .size */
+		&router_inode,		/* .ops */
+		&config_get_info,	/* .get_info */
+		NULL,			/* .fill_node */
+		NULL,			/* .next */
+		NULL,			/* .parent */
+		NULL,			/* .subdir */
+		NULL,			/* .data */
+	};
+
+	/*
+	 *	/proc/net/router/status 
+	 */
+	 
+	static struct proc_dir_entry proc_router_stat =
+	{
+		0,			/* .low_ino */
+		sizeof(name_stat) - 1,	/* .namelen */
+		name_stat,		/* .name */
+		0444 | S_IFREG,		/* .mode */
+		1,			/* .nlink */
+		0,			/* .uid */
+		0,			/* .gid */
+		0,			/* .size */
+		&router_inode,		/* .ops */
+		status_get_info,	/* .get_info */
+		NULL,			/* .fill_node */
+		NULL,			/* .next */
+		NULL,			/* .parent */
+		NULL,			/* .subdir */
+		NULL,			/* .data */
+	};
+
+	/* Strings */
+	static char conf_hdr[] =
+		"Device name    | port |IRQ|DMA|  mem.addr  |mem.size|"
+		"option1|option2|option3|option4\n";
+		
+	static char stat_hdr[] =
+		"Device name    |protocol|station|interface|clocking|baud rate| MTU |ndev"
+		"|link state\n";
+
+
+	/*
+	 *	Interface functions
+	 */
+
+	/*
+	 *	Initialize router proc interface.
+	 */
+
+#ifdef LINUX_2_1
+	__initfunc(int wanrouter_proc_init (void))
+	{
+		int err = proc_register(proc_net, &proc_router);
+
+		if (!err) {
+			proc_register(&proc_router, &proc_router_conf);
+			proc_register(&proc_router, &proc_router_stat);
+		}
+		return err;
+	}
+#else
+	int wanrouter_proc_init (void)
+	{
+		int err = proc_register_dynamic(&proc_net, &proc_router);
+
+		if (!err) {
+			proc_register_dynamic(&proc_router, &proc_router_conf);
+			proc_register_dynamic(&proc_router, &proc_router_stat);
+		}
+		return err;
+	}
+#endif
 
-static ssize_t router_proc_read(struct file* file, char* buf, size_t count,
-				loff_t *ppos)
-{
-	struct inode *inode = file->f_dentry->d_inode;
-	struct proc_dir_entry* dent;
-	char* page;
-	int pos, offs, len;
+	/*
+	 *	Clean up router proc interface.
+	 */
+
+	void wanrouter_proc_cleanup (void)
+	{
+		proc_unregister(&proc_router, proc_router_conf.low_ino);
+		proc_unregister(&proc_router, proc_router_stat.low_ino);
+#ifdef LINUX_2_1
+		proc_unregister(proc_net, proc_router.low_ino);
+#else
+		proc_unregister(&proc_net, proc_router.low_ino);
+#endif
+	}
 
-	if (count <= 0)
-		return 0;
-		
-	dent = inode->u.generic_ip;
-	if ((dent == NULL) || (dent->get_info == NULL))
-		return 0;
+	/*
+	 *	Add directory entry for WAN device.
+	 */
+
+	int wanrouter_proc_add (wan_device_t* wandev)
+	{
+		if (wandev->magic != ROUTER_MAGIC)
+			return -EINVAL;
 		
-	page = kmalloc(PROC_BUFSZ, GFP_KERNEL);
-	if (page == NULL)
-		return -ENOBUFS;
-		
-	pos = dent->get_info(page, dent->data, 0, 0);
-	offs = file->f_pos;
-	if (offs < pos) {
-		len = min(pos - offs, count);
-		if(copy_to_user(buf, (page + offs), len)) {
-			len = -EFAULT;
-			goto out;
-		}
-		file->f_pos += len;
-	}
-	else
-		len = 0;
-out:	kfree(page);
-	return len;
-}
-
-/*
- *	Prepare data for reading 'Config' entry.
- *	Return length of data.
- */
+		memset(&wandev->dent, 0, sizeof(wandev->dent));
+		wandev->dent.namelen	= strlen(wandev->name);
+		wandev->dent.name	= wandev->name;
+		wandev->dent.mode	= 0444 | S_IFREG;
+		wandev->dent.nlink	= 1;
+		wandev->dent.ops	= &wandev_inode;
+		wandev->dent.get_info	= &wandev_get_info;
+		wandev->dent.data	= wandev;
+#ifdef LINUX_2_1
+		return proc_register(&proc_router, &wandev->dent);
+#else
+		return proc_register_dynamic(&proc_router, &wandev->dent);
+#endif
+	}
 
-static int config_get_info(char* buf, char** start, off_t offs, int len)
-{
-	int cnt = sizeof(conf_hdr) - 1;
-	wan_device_t* wandev;
-	strcpy(buf, conf_hdr);
-	for (wandev = router_devlist;
-	     wandev && (cnt < (PROC_BUFSZ - 120));
-	     wandev = wandev->next) {
-		if (wandev->state) cnt += sprintf(&buf[cnt],
-			"%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n",
-			wandev->name,
-			wandev->ioport,
-			wandev->irq,
-			wandev->dma,
-			wandev->maddr,
-			wandev->msize,
-			wandev->hw_opt[0],
-			wandev->hw_opt[1],
-			wandev->hw_opt[2],
-			wandev->hw_opt[3]);
+	/*
+	 *	Delete directory entry for WAN device.
+	 */
+	 
+	int wanrouter_proc_delete(wan_device_t* wandev)
+	{
+		if (wandev->magic != ROUTER_MAGIC)
+			return -EINVAL;
+		proc_unregister(&proc_router, wandev->dent.low_ino);
+		return 0;
 	}
 
-	return cnt;
-}
+	/****** Proc filesystem entry points ****************************************/
 
-/*
- *	Prepare data for reading 'Status' entry.
- *	Return length of data.
- */
+	/*
+	 *	Verify access rights.
+	 */
 
-static int status_get_info(char* buf, char** start, off_t offs, int len)
-{
-	int cnt = 0;
-	wan_device_t* wandev;
+	static int router_proc_perms (struct inode* inode, int op)
+	{
+		return 0;
+	}
 
-	cnt += sprintf(&buf[cnt], "\nSTATUS FOR PORT 0\n\n");
-	strcpy(&buf[cnt], stat_hdr);
-	cnt += sizeof(stat_hdr) - 1;
-
-	for (wandev = router_devlist;
-	     wandev && (cnt < (PROC_BUFSZ - 80));
-	     wandev = wandev->next) {
-		if (!wandev->state) continue;
-		cnt += sprintf(&buf[cnt],
-			"%-15s|%-7s|%-9s|%-8s|%9u|%5u|%3u |",
-			wandev->name,
-			wandev->station ? " DCE" : " DTE",
-			wandev->interface ? " V.35" : " RS-232",
-			wandev->clocking ? "internal" : "external",
-			wandev->bps,
-			wandev->mtu,
-			wandev->ndev);
-
-		switch (wandev->state) {
-
-		case WAN_UNCONFIGURED:
-			cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured");
-			break;
-
-		case WAN_DISCONNECTED:
-			cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected");
-			break;
-
-		case WAN_CONNECTING:
-			cnt += sprintf(&buf[cnt], "%-12s\n", "connecting");
-			break;
-
-		case WAN_CONNECTED:
-			cnt += sprintf(&buf[cnt], "%-12s\n", "connected");
-			break;
-
-		default:
-			cnt += sprintf(&buf[cnt], "%-12s\n", "invalid");
-			break;
+	/*
+	 *	Read router proc directory entry.
+	 *	This is universal routine for reading all entries in /proc/net/wanrouter
+	 *	directory.  Each directory entry contains a pointer to the 'method' for
+	 *	preparing data for that entry.
+	 *	o verify arguments
+	 *	o allocate kernel buffer
+	 *	o call get_info() to prepare data
+	 *	o copy data to user space
+	 *	o release kernel buffer
+	 *
+	 *	Return:	number of bytes copied to user space (0, if no data)
+	 *		<0	error
+	 */
+#ifdef LINUX_2_1
+	static ssize_t router_proc_read(struct file* file, char* buf, size_t count,
+					loff_t *ppos)
+	{
+		struct inode *inode = file->f_dentry->d_inode;
+		struct proc_dir_entry* dent;
+		char* page;
+		int pos, offs, len;
+
+		if (count <= 0)
+			return 0;
+			
+		dent = inode->u.generic_ip;
+		if ((dent == NULL) || (dent->get_info == NULL))
+			return 0;
+			
+		page = kmalloc(PROC_BUFSZ, GFP_KERNEL);
+		if (page == NULL)
+			return -ENOBUFS;
+			
+		pos = dent->get_info(page, dent->data, 0, 0, 0);
+		offs = file->f_pos;
+		if (offs < pos) {
+			len = min(pos - offs, count);
+			if(copy_to_user(buf, (page + offs), len))
+				return -EFAULT;
+			file->f_pos += len;
 		}
+		else
+			len = 0;
+		kfree(page);
+		return len;
 	}
-	return cnt;
-}
 
-/*
- *	Prepare data for reading <device> entry.
- *	Return length of data.
- *
- *	On entry, the 'start' argument will contain a pointer to WAN device
- *	data space.
- */
+#else
+	static int router_proc_read(
+		struct inode* inode, struct file* file, char* buf, int count)
+	{
+		struct proc_dir_entry* dent;
+		char* page;
+		int err, pos, offs, len;
+
+		if (count <= 0)
+			return 0;
+		dent = inode->u.generic_ip;
+		if ((dent == NULL) || (dent->get_info == NULL))
+			return -ENODATA;
+		err = verify_area(VERIFY_WRITE, buf, count);
+		if (err) return err;
+
+		page = kmalloc(PROC_BUFSZ, GFP_KERNEL);
+		if (page == NULL)
+			return -ENOMEM;
+
+		pos = dent->get_info(page, dent->data, 0, 0, 0);
+		offs = file->f_pos;
+		if (offs < pos) {
+			len = min(pos - offs, count);
+			memcpy_tofs((void*)buf, (void*)(page + offs), len);
+			file->f_pos += len;
+		}
+		else len = 0;
+		kfree(page);
+		return len;
+	}
+#endif
 
-static int wandev_get_info(char* buf, char** start, off_t offs, int len)
-{
-	wan_device_t* wandev = (void*)start;
-	int cnt = 0;
-	int rslt = 0;
 
-	if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC))
-		return 0;
-	if (!wandev->state)
-		return sprintf(&buf[cnt], "device is not configured!\n");
+	/*
+	 *	Prepare data for reading 'Config' entry.
+	 *	Return length of data.
+	 */
+
+	static int config_get_info(char* buf, char** start, off_t offs, int len, 
+		int dummy)
+	{
+		int cnt = sizeof(conf_hdr) - 1;
+		wan_device_t* wandev;
+		strcpy(buf, conf_hdr);
+		for (wandev = router_devlist;
+		     wandev && (cnt < (PROC_BUFSZ - 120));
+		     wandev = wandev->next) {
+			if (wandev->state) cnt += sprintf(&buf[cnt],
+				"%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n",
+				wandev->name,
+				wandev->ioport,
+				wandev->irq,
+				wandev->dma,
+				wandev->maddr,
+				wandev->msize,
+				wandev->hw_opt[0],
+				wandev->hw_opt[1],
+				wandev->hw_opt[2],
+				wandev->hw_opt[3]);
+		}
 
-	/* Update device statistics */
-	if (wandev->update) {
+		return cnt;
+	}
 
-		rslt = wandev->update(wandev);
-		if(rslt) {
-			switch (rslt) {
-			case -EAGAIN:
-				return sprintf(&buf[cnt], "Device is busy!\n");
+	/*
+	 *	Prepare data for reading 'Status' entry.
+	 *	Return length of data.
+	 */
+
+	static int status_get_info(char* buf, char** start, off_t offs, int len, 
+				int dummy)
+	{
+		int cnt = 0;
+		wan_device_t* wandev;
+
+		//cnt += sprintf(&buf[cnt], "\nSTATUS:\n\n");
+		strcpy(&buf[cnt], stat_hdr);
+		cnt += sizeof(stat_hdr) - 1;
+
+		for (wandev = router_devlist;
+		     wandev && (cnt < (PROC_BUFSZ - 80));
+		     wandev = wandev->next) {
+			if (!wandev->state) continue;
+			cnt += sprintf(&buf[cnt],
+				"%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |",
+				wandev->name,
+				PROT_DECODE(wandev->config_id),
+				wandev->config_id == WANCONFIG_FR ? 
+					(wandev->station ? " Node" : " CPE") :
+					(wandev->config_id == WANCONFIG_X25 ?
+					(wandev->station ? " DCE" : " DTE") :
+					(" N/A")),
+				wandev->interface ? " V.35" : " RS-232",
+				wandev->clocking ? "internal" : "external",
+				wandev->bps,
+				wandev->mtu,
+				wandev->ndev);
+
+			switch (wandev->state) {
+
+			case WAN_UNCONFIGURED:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured");
+				break;
+
+			case WAN_DISCONNECTED:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected");
+				break;
+
+			case WAN_CONNECTING:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "connecting");
+				break;
+
+			case WAN_CONNECTED:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "connected");
+				break;
+
+			case WAN_FT1_READY:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "ft1 ready");
+				break;
 
 			default:
-				return sprintf(&buf[cnt],
-					"Device is not configured!\n");
+				cnt += sprintf(&buf[cnt], "%-12s\n", "invalid");
+				break;
 			}
 		}
+		return cnt;
 	}
 
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "total packets received", wandev->stats.rx_packets);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "total packets transmitted", wandev->stats.tx_packets);
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "total bytes received", wandev->stats.rx_bytes);
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "total bytes transmitted", wandev->stats.tx_bytes);
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "bad packets received", wandev->stats.rx_errors);
-       	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "packet transmit problems", wandev->stats.tx_errors);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "received frames dropped", wandev->stats.rx_dropped);
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "transmit frames dropped", wandev->stats.tx_dropped);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "multicast packets received", wandev->stats.multicast);
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "transmit collisions", wandev->stats.collisions);
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "receive length errors", wandev->stats.rx_length_errors);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-		"receiver overrun errors", wandev->stats.rx_over_errors);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-		"CRC errors", wandev->stats.rx_crc_errors);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-		"frame format errors (aborts)", wandev->stats.rx_frame_errors);
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "receiver fifo overrun", wandev->stats.rx_fifo_errors);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-		"receiver missed packet", wandev->stats.rx_missed_errors);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-		"aborted frames transmitted", wandev->stats.tx_aborted_errors);
-  	return cnt;
-}
+	/*
+	 *	Prepare data for reading <device> entry.
+	 *	Return length of data.
+	 *
+	 *	On entry, the 'start' argument will contain a pointer to WAN device
+	 *	data space.
+	 */
+
+	static int wandev_get_info(char* buf, char** start, off_t offs, int len, 
+				int dummy)
+	{
+		wan_device_t* wandev = (void*)start;
+		int cnt = 0;
+		int rslt = 0;
+
+		if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC))
+			return 0;
+		if (!wandev->state)
+			return sprintf(&buf[cnt], "Device is not configured!\n");
+
+		/* Update device statistics */
+		if (wandev->update) {
+
+			rslt = wandev->update(wandev);
+			if(rslt) {
+				switch (rslt) {
+				case -EAGAIN:
+					return sprintf(&buf[cnt], "Device is busy!\n");
+
+				default:
+					return sprintf(&buf[cnt],
+						"Device is not configured!\n");
+				}
+			}
+		}
+
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total packets received", wandev->stats.rx_packets);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total packets transmitted", wandev->stats.tx_packets);
+#ifdef LINUX_2_1
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total bytes received", wandev->stats.rx_bytes);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total bytes transmitted", wandev->stats.tx_bytes);
+#endif
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"bad packets received", wandev->stats.rx_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"packet transmit problems", wandev->stats.tx_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"received frames dropped", wandev->stats.rx_dropped);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"transmit frames dropped", wandev->stats.tx_dropped);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"multicast packets received", wandev->stats.multicast);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"transmit collisions", wandev->stats.collisions);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receive length errors", wandev->stats.rx_length_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receiver overrun errors", wandev->stats.rx_over_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"CRC errors", wandev->stats.rx_crc_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"frame format errors (aborts)", wandev->stats.rx_frame_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receiver fifo overrun", wandev->stats.rx_fifo_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receiver missed packet", wandev->stats.rx_missed_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"aborted frames transmitted", wandev->stats.tx_aborted_errors);
+
+		return cnt;
+	}
+
+#endif /* End of ifdef LINUX_2_4 */
+
 
-/*
- *	End
- */
- 
 #else
 
 /*
  *	No /proc - output stubs
  */
- 
-int __init wanrouter_proc_init(void)
+
+__initfunc(int wanrouter_proc_init(void))
 {
 	return 0;
 }
@@ -436,6 +1055,33 @@
 	return 0;
 }
 
+#endif
+
+/*============================================================================
+ * Write WAN device ???.
+ * o Find WAN device associated with this node
+ */
+#ifdef LINUX_2_0
+static int device_write(
+        struct inode* inode, struct file* file, const char* buf, int count)
+{
+        int err = verify_area(VERIFY_READ, buf, count);
+        struct proc_dir_entry* dent;
+        wan_device_t* wandev;
+
+        if (err) return err;
+
+        dent = inode->u.generic_ip;
+        if ((dent == NULL) || (dent->data == NULL))
+                return -ENODATA;
+
+        wandev = dent->data;
+
+        printk(KERN_ERR "%s: writing %d bytes to %s...\n",
+                name_root, count, dent->name);
+        
+	return 0;
+}
 #endif
 
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)