diff options
Diffstat (limited to 'net/wanrouter/wanproc.c')
-rw-r--r-- | net/wanrouter/wanproc.c | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c new file mode 100644 index 00000000000..c28ba5a4720 --- /dev/null +++ b/net/wanrouter/wanproc.c @@ -0,0 +1,381 @@ +/***************************************************************************** +* wanproc.c WAN Router Module. /proc filesystem interface. +* +* This module is completely hardware-independent and provides +* access to the router using Linux /proc filesystem. +* +* Author: Gideon Hack +* +* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* 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 +* Jan 30, 1997 Alan Cox Hacked around for 2.1 +* Dec 13, 1996 Gene Kozin Initial version (based on Sangoma's WANPIPE) +*****************************************************************************/ + +#include <linux/config.h> +#include <linux/init.h> /* __initfunc et al. */ +#include <linux/stddef.h> /* offsetof(), etc. */ +#include <linux/errno.h> /* return codes */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/wanrouter.h> /* WAN router API definitions */ +#include <linux/seq_file.h> +#include <linux/smp_lock.h> + +#include <asm/io.h> + +#define PROC_STATS_FORMAT "%30s: %12lu\n" + +/****** Defines and Macros **************************************************/ + +#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" ) + +/****** Function Prototypes *************************************************/ + +#ifdef CONFIG_PROC_FS + +/* 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 + */ + +/* + * /proc/net/router + */ + +static struct proc_dir_entry *proc_router; + +/* Strings */ + +/* + * Interface functions + */ + +/****** Proc filesystem entry points ****************************************/ + +/* + * Iterator + */ +static void *r_start(struct seq_file *m, loff_t *pos) +{ + struct wan_device *wandev; + loff_t l = *pos; + + lock_kernel(); + if (!l--) + return SEQ_START_TOKEN; + for (wandev = wanrouter_router_devlist; l-- && wandev; + wandev = wandev->next) + ; + return wandev; +} + +static void *r_next(struct seq_file *m, void *v, loff_t *pos) +{ + struct wan_device *wandev = v; + (*pos)++; + return (v == SEQ_START_TOKEN) ? wanrouter_router_devlist : wandev->next; +} + +static void r_stop(struct seq_file *m, void *v) +{ + unlock_kernel(); +} + +static int config_show(struct seq_file *m, void *v) +{ + struct wan_device *p = v; + if (v == SEQ_START_TOKEN) { + seq_puts(m, "Device name | port |IRQ|DMA| mem.addr |" + "mem.size|option1|option2|option3|option4\n"); + return 0; + } + if (!p->state) + return 0; + seq_printf(m, "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n", + p->name, p->ioport, p->irq, p->dma, p->maddr, p->msize, + p->hw_opt[0], p->hw_opt[1], p->hw_opt[2], p->hw_opt[3]); + return 0; +} + +static int status_show(struct seq_file *m, void *v) +{ + struct wan_device *p = v; + if (v == SEQ_START_TOKEN) { + seq_puts(m, "Device name |protocol|station|interface|" + "clocking|baud rate| MTU |ndev|link state\n"); + return 0; + } + if (!p->state) + return 0; + seq_printf(m, "%-15s|%-8s| %-7s| %-9s|%-8s|%9u|%5u|%3u |", + p->name, + PROT_DECODE(p->config_id), + p->config_id == WANCONFIG_FR ? + (p->station ? "Node" : "CPE") : + (p->config_id == WANCONFIG_X25 ? + (p->station ? "DCE" : "DTE") : + ("N/A")), + p->interface ? "V.35" : "RS-232", + p->clocking ? "internal" : "external", + p->bps, + p->mtu, + p->ndev); + + switch (p->state) { + case WAN_UNCONFIGURED: + seq_printf(m, "%-12s\n", "unconfigured"); + break; + case WAN_DISCONNECTED: + seq_printf(m, "%-12s\n", "disconnected"); + break; + case WAN_CONNECTING: + seq_printf(m, "%-12s\n", "connecting"); + break; + case WAN_CONNECTED: + seq_printf(m, "%-12s\n", "connected"); + break; + default: + seq_printf(m, "%-12s\n", "invalid"); + break; + } + return 0; +} + +static struct seq_operations config_op = { + .start = r_start, + .next = r_next, + .stop = r_stop, + .show = config_show, +}; + +static struct seq_operations status_op = { + .start = r_start, + .next = r_next, + .stop = r_stop, + .show = status_show, +}; + +static int config_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &config_op); +} + +static int status_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &status_op); +} + +static struct file_operations config_fops = { + .owner = THIS_MODULE, + .open = config_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static struct file_operations status_fops = { + .owner = THIS_MODULE, + .open = status_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int wandev_show(struct seq_file *m, void *v) +{ + struct wan_device *wandev = m->private; + + if (wandev->magic != ROUTER_MAGIC) + return 0; + + if (!wandev->state) { + seq_puts(m, "device is not configured!\n"); + return 0; + } + + /* Update device statistics */ + if (wandev->update) { + int err = wandev->update(wandev); + if (err == -EAGAIN) { + seq_puts(m, "Device is busy!\n"); + return 0; + } + if (err) { + seq_puts(m, "Device is not configured!\n"); + return 0; + } + } + + seq_printf(m, PROC_STATS_FORMAT, + "total packets received", wandev->stats.rx_packets); + seq_printf(m, PROC_STATS_FORMAT, + "total packets transmitted", wandev->stats.tx_packets); + seq_printf(m, PROC_STATS_FORMAT, + "total bytes received", wandev->stats.rx_bytes); + seq_printf(m, PROC_STATS_FORMAT, + "total bytes transmitted", wandev->stats.tx_bytes); + seq_printf(m, PROC_STATS_FORMAT, + "bad packets received", wandev->stats.rx_errors); + seq_printf(m, PROC_STATS_FORMAT, + "packet transmit problems", wandev->stats.tx_errors); + seq_printf(m, PROC_STATS_FORMAT, + "received frames dropped", wandev->stats.rx_dropped); + seq_printf(m, PROC_STATS_FORMAT, + "transmit frames dropped", wandev->stats.tx_dropped); + seq_printf(m, PROC_STATS_FORMAT, + "multicast packets received", wandev->stats.multicast); + seq_printf(m, PROC_STATS_FORMAT, + "transmit collisions", wandev->stats.collisions); + seq_printf(m, PROC_STATS_FORMAT, + "receive length errors", wandev->stats.rx_length_errors); + seq_printf(m, PROC_STATS_FORMAT, + "receiver overrun errors", wandev->stats.rx_over_errors); + seq_printf(m, PROC_STATS_FORMAT, + "CRC errors", wandev->stats.rx_crc_errors); + seq_printf(m, PROC_STATS_FORMAT, + "frame format errors (aborts)", wandev->stats.rx_frame_errors); + seq_printf(m, PROC_STATS_FORMAT, + "receiver fifo overrun", wandev->stats.rx_fifo_errors); + seq_printf(m, PROC_STATS_FORMAT, + "receiver missed packet", wandev->stats.rx_missed_errors); + seq_printf(m, PROC_STATS_FORMAT, + "aborted frames transmitted", wandev->stats.tx_aborted_errors); + return 0; +} + +static int wandev_open(struct inode *inode, struct file *file) +{ + return single_open(file, wandev_show, PDE(inode)->data); +} + +static struct file_operations wandev_fops = { + .owner = THIS_MODULE, + .open = wandev_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .ioctl = wanrouter_ioctl, +}; + +/* + * 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", S_IRUGO, proc_router); + if (!p) + goto fail_config; + p->proc_fops = &config_fops; + p = create_proc_entry("status", S_IRUGO, proc_router); + if (!p) + goto fail_stat; + p->proc_fops = &status_fops; + return 0; +fail_stat: + remove_proc_entry("config", proc_router); +fail_config: + remove_proc_entry(ROUTER_NAME, proc_net); +fail: + return -ENOMEM; +} + +/* + * 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); +} + +/* + * Add directory entry for WAN device. + */ + +int wanrouter_proc_add(struct wan_device* wandev) +{ + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + + wandev->dent = create_proc_entry(wandev->name, S_IRUGO, proc_router); + if (!wandev->dent) + return -ENOMEM; + wandev->dent->proc_fops = &wandev_fops; + wandev->dent->data = wandev; + return 0; +} + +/* + * Delete directory entry for WAN device. + */ +int wanrouter_proc_delete(struct wan_device* wandev) +{ + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + remove_proc_entry(wandev->name, proc_router); + return 0; +} + +#else + +/* + * No /proc - output stubs + */ + +int __init wanrouter_proc_init(void) +{ + return 0; +} + +void wanrouter_proc_cleanup(void) +{ +} + +int wanrouter_proc_add(struct wan_device *wandev) +{ + return 0; +} + +int wanrouter_proc_delete(struct wan_device *wandev) +{ + return 0; +} + +#endif + +/* + * End + */ + |