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/init.h> /* __initfunc et al. */ 24#include <linux/stddef.h> /* offsetof(), etc. */ 25#include <linux/errno.h> /* return codes */ 26#include <linux/kernel.h> 27#include <linux/module.h> 28#include <linux/wanrouter.h> /* WAN router API definitions */ 29#include <linux/seq_file.h> 30#include <linux/mutex.h> 31 32#include <net/net_namespace.h> 33#include <asm/io.h> 34 35#define PROC_STATS_FORMAT "%30s: %12lu\n" 36 37/****** Defines and Macros **************************************************/ 38 39#define PROT_DECODE(prot) ((prot == WANCONFIG_FR) ? " FR" :\ 40 (prot == WANCONFIG_X25) ? " X25" : \ 41 (prot == WANCONFIG_PPP) ? " PPP" : \ 42 (prot == WANCONFIG_CHDLC) ? " CHDLC": \ 43 (prot == WANCONFIG_MPPP) ? " MPPP" : \ 44 " Unknown" ) 45 46/****** Function Prototypes *************************************************/ 47 48#ifdef CONFIG_PROC_FS 49 50/* Miscellaneous */ 51 52/* 53 * Structures for interfacing with the /proc filesystem. 54 * Router creates its own directory /proc/net/router with the folowing 55 * entries: 56 * config device configuration 57 * status global device statistics 58 * <device> entry for each WAN device 59 */ 60 61/* 62 * Generic /proc/net/router/<file> file and inode operations 63 */ 64 65/* 66 * /proc/net/router 67 */ 68 69static DEFINE_MUTEX(config_mutex); 70static struct proc_dir_entry *proc_router; 71 72/* Strings */ 73 74/* 75 * Interface functions 76 */ 77 78/****** Proc filesystem entry points ****************************************/ 79 80/* 81 * Iterator 82 */ 83static void *r_start(struct seq_file *m, loff_t *pos) 84 __acquires(kernel_lock) 85{ 86 struct wan_device *wandev; 87 loff_t l = *pos; 88 89 mutex_lock(&config_mutex); 90 if (!l--) 91 return SEQ_START_TOKEN; 92 for (wandev = wanrouter_router_devlist; l-- && wandev; 93 wandev = wandev->next) 94 ; 95 return wandev; 96} 97 98static void *r_next(struct seq_file *m, void *v, loff_t *pos) 99{ 100 struct wan_device *wandev = v; 101 (*pos)++; 102 return (v == SEQ_START_TOKEN) ? wanrouter_router_devlist : wandev->next; 103} 104 105static void r_stop(struct seq_file *m, void *v) 106 __releases(kernel_lock) 107{ 108 mutex_unlock(&config_mutex); 109} 110 111static int config_show(struct seq_file *m, void *v) 112{ 113 struct wan_device *p = v; 114 if (v == SEQ_START_TOKEN) { 115 seq_puts(m, "Device name | port |IRQ|DMA| mem.addr |" 116 "mem.size|option1|option2|option3|option4\n"); 117 return 0; 118 } 119 if (!p->state) 120 return 0; 121 seq_printf(m, "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n", 122 p->name, p->ioport, p->irq, p->dma, p->maddr, p->msize, 123 p->hw_opt[0], p->hw_opt[1], p->hw_opt[2], p->hw_opt[3]); 124 return 0; 125} 126 127static int status_show(struct seq_file *m, void *v) 128{ 129 struct wan_device *p = v; 130 if (v == SEQ_START_TOKEN) { 131 seq_puts(m, "Device name |protocol|station|interface|" 132 "clocking|baud rate| MTU |ndev|link state\n"); 133 return 0; 134 } 135 if (!p->state) 136 return 0; 137 seq_printf(m, "%-15s|%-8s| %-7s| %-9s|%-8s|%9u|%5u|%3u |", 138 p->name, 139 PROT_DECODE(p->config_id), 140 p->config_id == WANCONFIG_FR ? 141 (p->station ? "Node" : "CPE") : 142 (p->config_id == WANCONFIG_X25 ? 143 (p->station ? "DCE" : "DTE") : 144 ("N/A")), 145 p->interface ? "V.35" : "RS-232", 146 p->clocking ? "internal" : "external", 147 p->bps, 148 p->mtu, 149 p->ndev); 150 151 switch (p->state) { 152 case WAN_UNCONFIGURED: 153 seq_printf(m, "%-12s\n", "unconfigured"); 154 break; 155 case WAN_DISCONNECTED: 156 seq_printf(m, "%-12s\n", "disconnected"); 157 break; 158 case WAN_CONNECTING: 159 seq_printf(m, "%-12s\n", "connecting"); 160 break; 161 case WAN_CONNECTED: 162 seq_printf(m, "%-12s\n", "connected"); 163 break; 164 default: 165 seq_printf(m, "%-12s\n", "invalid"); 166 break; 167 } 168 return 0; 169} 170 171static const struct seq_operations config_op = { 172 .start = r_start, 173 .next = r_next, 174 .stop = r_stop, 175 .show = config_show, 176}; 177 178static const struct seq_operations status_op = { 179 .start = r_start, 180 .next = r_next, 181 .stop = r_stop, 182 .show = status_show, 183}; 184 185static int config_open(struct inode *inode, struct file *file) 186{ 187 return seq_open(file, &config_op); 188} 189 190static int status_open(struct inode *inode, struct file *file) 191{ 192 return seq_open(file, &status_op); 193} 194 195static const struct file_operations config_fops = { 196 .owner = THIS_MODULE, 197 .open = config_open, 198 .read = seq_read, 199 .llseek = seq_lseek, 200 .release = seq_release, 201}; 202 203static const struct file_operations status_fops = { 204 .owner = THIS_MODULE, 205 .open = status_open, 206 .read = seq_read, 207 .llseek = seq_lseek, 208 .release = seq_release, 209}; 210 211static int wandev_show(struct seq_file *m, void *v) 212{ 213 struct wan_device *wandev = m->private; 214 215 if (wandev->magic != ROUTER_MAGIC) 216 return 0; 217 218 if (!wandev->state) { 219 seq_puts(m, "device is not configured!\n"); 220 return 0; 221 } 222 223 /* Update device statistics */ 224 if (wandev->update) { 225 int err = wandev->update(wandev); 226 if (err == -EAGAIN) { 227 seq_puts(m, "Device is busy!\n"); 228 return 0; 229 } 230 if (err) { 231 seq_puts(m, "Device is not configured!\n"); 232 return 0; 233 } 234 } 235 236 seq_printf(m, PROC_STATS_FORMAT, 237 "total packets received", wandev->stats.rx_packets); 238 seq_printf(m, PROC_STATS_FORMAT, 239 "total packets transmitted", wandev->stats.tx_packets); 240 seq_printf(m, PROC_STATS_FORMAT, 241 "total bytes received", wandev->stats.rx_bytes); 242 seq_printf(m, PROC_STATS_FORMAT, 243 "total bytes transmitted", wandev->stats.tx_bytes); 244 seq_printf(m, PROC_STATS_FORMAT, 245 "bad packets received", wandev->stats.rx_errors); 246 seq_printf(m, PROC_STATS_FORMAT, 247 "packet transmit problems", wandev->stats.tx_errors); 248 seq_printf(m, PROC_STATS_FORMAT, 249 "received frames dropped", wandev->stats.rx_dropped); 250 seq_printf(m, PROC_STATS_FORMAT, 251 "transmit frames dropped", wandev->stats.tx_dropped); 252 seq_printf(m, PROC_STATS_FORMAT, 253 "multicast packets received", wandev->stats.multicast); 254 seq_printf(m, PROC_STATS_FORMAT, 255 "transmit collisions", wandev->stats.collisions); 256 seq_printf(m, PROC_STATS_FORMAT, 257 "receive length errors", wandev->stats.rx_length_errors); 258 seq_printf(m, PROC_STATS_FORMAT, 259 "receiver overrun errors", wandev->stats.rx_over_errors); 260 seq_printf(m, PROC_STATS_FORMAT, 261 "CRC errors", wandev->stats.rx_crc_errors); 262 seq_printf(m, PROC_STATS_FORMAT, 263 "frame format errors (aborts)", wandev->stats.rx_frame_errors); 264 seq_printf(m, PROC_STATS_FORMAT, 265 "receiver fifo overrun", wandev->stats.rx_fifo_errors); 266 seq_printf(m, PROC_STATS_FORMAT, 267 "receiver missed packet", wandev->stats.rx_missed_errors); 268 seq_printf(m, PROC_STATS_FORMAT, 269 "aborted frames transmitted", wandev->stats.tx_aborted_errors); 270 return 0; 271} 272 273static int wandev_open(struct inode *inode, struct file *file) 274{ 275 return single_open(file, wandev_show, PDE(inode)->data); 276} 277 278static const struct file_operations wandev_fops = { 279 .owner = THIS_MODULE, 280 .open = wandev_open, 281 .read = seq_read, 282 .llseek = seq_lseek, 283 .release = single_release, 284 .unlocked_ioctl = wanrouter_ioctl, 285}; 286 287/* 288 * Initialize router proc interface. 289 */ 290 291int __init wanrouter_proc_init(void) 292{ 293 struct proc_dir_entry *p; 294 proc_router = proc_mkdir(ROUTER_NAME, init_net.proc_net); 295 if (!proc_router) 296 goto fail; 297 298 p = proc_create("config", S_IRUGO, proc_router, &config_fops); 299 if (!p) 300 goto fail_config; 301 p = proc_create("status", S_IRUGO, proc_router, &status_fops); 302 if (!p) 303 goto fail_stat; 304 return 0; 305fail_stat: 306 remove_proc_entry("config", proc_router); 307fail_config: 308 remove_proc_entry(ROUTER_NAME, init_net.proc_net); 309fail: 310 return -ENOMEM; 311} 312 313/* 314 * Clean up router proc interface. 315 */ 316 317void wanrouter_proc_cleanup(void) 318{ 319 remove_proc_entry("config", proc_router); 320 remove_proc_entry("status", proc_router); 321 remove_proc_entry(ROUTER_NAME, init_net.proc_net); 322} 323 324/* 325 * Add directory entry for WAN device. 326 */ 327 328int wanrouter_proc_add(struct wan_device* wandev) 329{ 330 if (wandev->magic != ROUTER_MAGIC) 331 return -EINVAL; 332 333 wandev->dent = proc_create(wandev->name, S_IRUGO, 334 proc_router, &wandev_fops); 335 if (!wandev->dent) 336 return -ENOMEM; 337 wandev->dent->data = wandev; 338 return 0; 339} 340 341/* 342 * Delete directory entry for WAN device. 343 */ 344int wanrouter_proc_delete(struct wan_device* wandev) 345{ 346 if (wandev->magic != ROUTER_MAGIC) 347 return -EINVAL; 348 remove_proc_entry(wandev->name, proc_router); 349 return 0; 350} 351 352#else 353 354/* 355 * No /proc - output stubs 356 */ 357 358int __init wanrouter_proc_init(void) 359{ 360 return 0; 361} 362 363void wanrouter_proc_cleanup(void) 364{ 365} 366 367int wanrouter_proc_add(struct wan_device *wandev) 368{ 369 return 0; 370} 371 372int wanrouter_proc_delete(struct wan_device *wandev) 373{ 374 return 0; 375} 376 377#endif 378 379/* 380 * End 381 */ 382