blob: c43612ee96bb517ea2b2f806e5e999e39c6cbc0c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*****************************************************************************
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#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>
Arnd Bergmann15fd0cd2010-07-11 11:18:57 +000030#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020032#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#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" : \
YOSHIFUJI Hideaki4ba61222007-02-09 23:25:25 +090041 (prot == WANCONFIG_PPP) ? " PPP" : \
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 (prot == WANCONFIG_CHDLC) ? " CHDLC": \
43 (prot == WANCONFIG_MPPP) ? " MPPP" : \
YOSHIFUJI Hideaki4ba61222007-02-09 23:25:25 +090044 " Unknown" )
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46/****** Function Prototypes *************************************************/
47
48#ifdef CONFIG_PROC_FS
49
50/* Miscellaneous */
51
52/*
53 * Structures for interfacing with the /proc filesystem.
Lucas De Marchi25985ed2011-03-30 22:57:33 -030054 * Router creates its own directory /proc/net/router with the following
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 * 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
Arnd Bergmann15fd0cd2010-07-11 11:18:57 +000069static DEFINE_MUTEX(config_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static 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{
85 struct wan_device *wandev;
86 loff_t l = *pos;
87
Arnd Bergmann15fd0cd2010-07-11 11:18:57 +000088 mutex_lock(&config_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 if (!l--)
90 return SEQ_START_TOKEN;
91 for (wandev = wanrouter_router_devlist; l-- && wandev;
92 wandev = wandev->next)
93 ;
94 return wandev;
95}
96
97static void *r_next(struct seq_file *m, void *v, loff_t *pos)
98{
99 struct wan_device *wandev = v;
100 (*pos)++;
101 return (v == SEQ_START_TOKEN) ? wanrouter_router_devlist : wandev->next;
102}
103
104static void r_stop(struct seq_file *m, void *v)
105{
Arnd Bergmann15fd0cd2010-07-11 11:18:57 +0000106 mutex_unlock(&config_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107}
108
109static int config_show(struct seq_file *m, void *v)
110{
111 struct wan_device *p = v;
112 if (v == SEQ_START_TOKEN) {
113 seq_puts(m, "Device name | port |IRQ|DMA| mem.addr |"
114 "mem.size|option1|option2|option3|option4\n");
115 return 0;
116 }
117 if (!p->state)
118 return 0;
119 seq_printf(m, "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n",
120 p->name, p->ioport, p->irq, p->dma, p->maddr, p->msize,
121 p->hw_opt[0], p->hw_opt[1], p->hw_opt[2], p->hw_opt[3]);
122 return 0;
123}
124
125static int status_show(struct seq_file *m, void *v)
126{
127 struct wan_device *p = v;
128 if (v == SEQ_START_TOKEN) {
129 seq_puts(m, "Device name |protocol|station|interface|"
130 "clocking|baud rate| MTU |ndev|link state\n");
131 return 0;
132 }
133 if (!p->state)
134 return 0;
135 seq_printf(m, "%-15s|%-8s| %-7s| %-9s|%-8s|%9u|%5u|%3u |",
136 p->name,
137 PROT_DECODE(p->config_id),
138 p->config_id == WANCONFIG_FR ?
139 (p->station ? "Node" : "CPE") :
140 (p->config_id == WANCONFIG_X25 ?
141 (p->station ? "DCE" : "DTE") :
142 ("N/A")),
143 p->interface ? "V.35" : "RS-232",
144 p->clocking ? "internal" : "external",
145 p->bps,
146 p->mtu,
147 p->ndev);
148
149 switch (p->state) {
150 case WAN_UNCONFIGURED:
151 seq_printf(m, "%-12s\n", "unconfigured");
152 break;
153 case WAN_DISCONNECTED:
154 seq_printf(m, "%-12s\n", "disconnected");
155 break;
156 case WAN_CONNECTING:
157 seq_printf(m, "%-12s\n", "connecting");
158 break;
159 case WAN_CONNECTED:
160 seq_printf(m, "%-12s\n", "connected");
161 break;
162 default:
163 seq_printf(m, "%-12s\n", "invalid");
164 break;
165 }
166 return 0;
167}
168
Philippe De Muyter56b3d972007-07-10 23:07:31 -0700169static const struct seq_operations config_op = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 .start = r_start,
171 .next = r_next,
172 .stop = r_stop,
173 .show = config_show,
174};
175
Philippe De Muyter56b3d972007-07-10 23:07:31 -0700176static const struct seq_operations status_op = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 .start = r_start,
178 .next = r_next,
179 .stop = r_stop,
180 .show = status_show,
181};
182
183static int config_open(struct inode *inode, struct file *file)
184{
185 return seq_open(file, &config_op);
186}
187
188static int status_open(struct inode *inode, struct file *file)
189{
190 return seq_open(file, &status_op);
191}
192
Arjan van de Venda7071d2007-02-12 00:55:36 -0800193static const struct file_operations config_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 .owner = THIS_MODULE,
195 .open = config_open,
196 .read = seq_read,
197 .llseek = seq_lseek,
198 .release = seq_release,
199};
200
Arjan van de Venda7071d2007-02-12 00:55:36 -0800201static const struct file_operations status_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 .owner = THIS_MODULE,
203 .open = status_open,
204 .read = seq_read,
205 .llseek = seq_lseek,
206 .release = seq_release,
207};
208
209static int wandev_show(struct seq_file *m, void *v)
210{
211 struct wan_device *wandev = m->private;
212
213 if (wandev->magic != ROUTER_MAGIC)
214 return 0;
215
216 if (!wandev->state) {
217 seq_puts(m, "device is not configured!\n");
218 return 0;
219 }
220
221 /* Update device statistics */
222 if (wandev->update) {
223 int err = wandev->update(wandev);
224 if (err == -EAGAIN) {
225 seq_puts(m, "Device is busy!\n");
226 return 0;
227 }
228 if (err) {
229 seq_puts(m, "Device is not configured!\n");
230 return 0;
231 }
232 }
233
234 seq_printf(m, PROC_STATS_FORMAT,
235 "total packets received", wandev->stats.rx_packets);
236 seq_printf(m, PROC_STATS_FORMAT,
237 "total packets transmitted", wandev->stats.tx_packets);
238 seq_printf(m, PROC_STATS_FORMAT,
239 "total bytes received", wandev->stats.rx_bytes);
240 seq_printf(m, PROC_STATS_FORMAT,
241 "total bytes transmitted", wandev->stats.tx_bytes);
242 seq_printf(m, PROC_STATS_FORMAT,
243 "bad packets received", wandev->stats.rx_errors);
244 seq_printf(m, PROC_STATS_FORMAT,
245 "packet transmit problems", wandev->stats.tx_errors);
246 seq_printf(m, PROC_STATS_FORMAT,
247 "received frames dropped", wandev->stats.rx_dropped);
248 seq_printf(m, PROC_STATS_FORMAT,
249 "transmit frames dropped", wandev->stats.tx_dropped);
250 seq_printf(m, PROC_STATS_FORMAT,
251 "multicast packets received", wandev->stats.multicast);
252 seq_printf(m, PROC_STATS_FORMAT,
253 "transmit collisions", wandev->stats.collisions);
254 seq_printf(m, PROC_STATS_FORMAT,
255 "receive length errors", wandev->stats.rx_length_errors);
256 seq_printf(m, PROC_STATS_FORMAT,
257 "receiver overrun errors", wandev->stats.rx_over_errors);
258 seq_printf(m, PROC_STATS_FORMAT,
259 "CRC errors", wandev->stats.rx_crc_errors);
260 seq_printf(m, PROC_STATS_FORMAT,
261 "frame format errors (aborts)", wandev->stats.rx_frame_errors);
262 seq_printf(m, PROC_STATS_FORMAT,
263 "receiver fifo overrun", wandev->stats.rx_fifo_errors);
264 seq_printf(m, PROC_STATS_FORMAT,
265 "receiver missed packet", wandev->stats.rx_missed_errors);
266 seq_printf(m, PROC_STATS_FORMAT,
267 "aborted frames transmitted", wandev->stats.tx_aborted_errors);
268 return 0;
269}
270
271static int wandev_open(struct inode *inode, struct file *file)
272{
273 return single_open(file, wandev_show, PDE(inode)->data);
274}
275
Arjan van de Venda7071d2007-02-12 00:55:36 -0800276static const struct file_operations wandev_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 .owner = THIS_MODULE,
278 .open = wandev_open,
279 .read = seq_read,
280 .llseek = seq_lseek,
281 .release = single_release,
Alan Cox866988e2008-05-25 23:41:40 -0700282 .unlocked_ioctl = wanrouter_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283};
284
285/*
286 * Initialize router proc interface.
287 */
288
289int __init wanrouter_proc_init(void)
290{
291 struct proc_dir_entry *p;
Eric W. Biederman457c4cb2007-09-12 12:01:34 +0200292 proc_router = proc_mkdir(ROUTER_NAME, init_net.proc_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 if (!proc_router)
294 goto fail;
295
Wang Chen6d37a152008-02-28 14:15:56 -0800296 p = proc_create("config", S_IRUGO, proc_router, &config_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 if (!p)
298 goto fail_config;
Wang Chen6d37a152008-02-28 14:15:56 -0800299 p = proc_create("status", S_IRUGO, proc_router, &status_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 if (!p)
301 goto fail_stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 return 0;
303fail_stat:
304 remove_proc_entry("config", proc_router);
305fail_config:
Eric W. Biederman457c4cb2007-09-12 12:01:34 +0200306 remove_proc_entry(ROUTER_NAME, init_net.proc_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307fail:
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);
Eric W. Biederman457c4cb2007-09-12 12:01:34 +0200319 remove_proc_entry(ROUTER_NAME, init_net.proc_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320}
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
Wang Chen6d37a152008-02-28 14:15:56 -0800331 wandev->dent = proc_create(wandev->name, S_IRUGO,
332 proc_router, &wandev_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 if (!wandev->dent)
334 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 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