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