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 following
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 
69 static DEFINE_MUTEX(config_mutex);
70 static 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  */
r_start(struct seq_file * m,loff_t * pos)83 static void *r_start(struct seq_file *m, loff_t *pos)
84 {
85 	struct wan_device *wandev;
86 	loff_t l = *pos;
87 
88 	mutex_lock(&config_mutex);
89 	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 
r_next(struct seq_file * m,void * v,loff_t * pos)97 static 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 
r_stop(struct seq_file * m,void * v)104 static void r_stop(struct seq_file *m, void *v)
105 {
106 	mutex_unlock(&config_mutex);
107 }
108 
config_show(struct seq_file * m,void * v)109 static 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 
status_show(struct seq_file * m,void * v)125 static 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 
169 static const struct seq_operations config_op = {
170 	.start	= r_start,
171 	.next	= r_next,
172 	.stop	= r_stop,
173 	.show	= config_show,
174 };
175 
176 static const struct seq_operations status_op = {
177 	.start	= r_start,
178 	.next	= r_next,
179 	.stop	= r_stop,
180 	.show	= status_show,
181 };
182 
config_open(struct inode * inode,struct file * file)183 static int config_open(struct inode *inode, struct file *file)
184 {
185 	return seq_open(file, &config_op);
186 }
187 
status_open(struct inode * inode,struct file * file)188 static int status_open(struct inode *inode, struct file *file)
189 {
190 	return seq_open(file, &status_op);
191 }
192 
193 static const struct file_operations config_fops = {
194 	.owner	 = THIS_MODULE,
195 	.open	 = config_open,
196 	.read	 = seq_read,
197 	.llseek	 = seq_lseek,
198 	.release = seq_release,
199 };
200 
201 static const struct file_operations status_fops = {
202 	.owner	 = THIS_MODULE,
203 	.open	 = status_open,
204 	.read	 = seq_read,
205 	.llseek	 = seq_lseek,
206 	.release = seq_release,
207 };
208 
wandev_show(struct seq_file * m,void * v)209 static 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 
wandev_open(struct inode * inode,struct file * file)271 static int wandev_open(struct inode *inode, struct file *file)
272 {
273 	return single_open(file, wandev_show, PDE(inode)->data);
274 }
275 
276 static const struct file_operations wandev_fops = {
277 	.owner	 = THIS_MODULE,
278 	.open	 = wandev_open,
279 	.read	 = seq_read,
280 	.llseek	 = seq_lseek,
281 	.release = single_release,
282 	.unlocked_ioctl  = wanrouter_ioctl,
283 };
284 
285 /*
286  *	Initialize router proc interface.
287  */
288 
wanrouter_proc_init(void)289 int __init wanrouter_proc_init(void)
290 {
291 	struct proc_dir_entry *p;
292 	proc_router = proc_mkdir(ROUTER_NAME, init_net.proc_net);
293 	if (!proc_router)
294 		goto fail;
295 
296 	p = proc_create("config", S_IRUGO, proc_router, &config_fops);
297 	if (!p)
298 		goto fail_config;
299 	p = proc_create("status", S_IRUGO, proc_router, &status_fops);
300 	if (!p)
301 		goto fail_stat;
302 	return 0;
303 fail_stat:
304 	remove_proc_entry("config", proc_router);
305 fail_config:
306 	remove_proc_entry(ROUTER_NAME, init_net.proc_net);
307 fail:
308 	return -ENOMEM;
309 }
310 
311 /*
312  *	Clean up router proc interface.
313  */
314 
wanrouter_proc_cleanup(void)315 void 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, init_net.proc_net);
320 }
321 
322 /*
323  *	Add directory entry for WAN device.
324  */
325 
wanrouter_proc_add(struct wan_device * wandev)326 int wanrouter_proc_add(struct wan_device* wandev)
327 {
328 	if (wandev->magic != ROUTER_MAGIC)
329 		return -EINVAL;
330 
331 	wandev->dent = proc_create(wandev->name, S_IRUGO,
332 				   proc_router, &wandev_fops);
333 	if (!wandev->dent)
334 		return -ENOMEM;
335 	wandev->dent->data	= wandev;
336 	return 0;
337 }
338 
339 /*
340  *	Delete directory entry for WAN device.
341  */
wanrouter_proc_delete(struct wan_device * wandev)342 int 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 
wanrouter_proc_init(void)356 int __init wanrouter_proc_init(void)
357 {
358 	return 0;
359 }
360 
wanrouter_proc_cleanup(void)361 void wanrouter_proc_cleanup(void)
362 {
363 }
364 
wanrouter_proc_add(struct wan_device * wandev)365 int wanrouter_proc_add(struct wan_device *wandev)
366 {
367 	return 0;
368 }
369 
wanrouter_proc_delete(struct wan_device * wandev)370 int wanrouter_proc_delete(struct wan_device *wandev)
371 {
372 	return 0;
373 }
374 
375 #endif
376 
377 /*
378  *	End
379  */
380 
381