Root/
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 <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 | |
69 | static struct proc_dir_entry *proc_router; |
70 | |
71 | /* Strings */ |
72 | |
73 | /* |
74 | * Interface functions |
75 | */ |
76 | |
77 | /****** Proc filesystem entry points ****************************************/ |
78 | |
79 | /* |
80 | * Iterator |
81 | */ |
82 | static void *r_start(struct seq_file *m, loff_t *pos) |
83 | __acquires(kernel_lock) |
84 | { |
85 | struct wan_device *wandev; |
86 | loff_t l = *pos; |
87 | |
88 | lock_kernel(); |
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 | |
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 | |
104 | static void r_stop(struct seq_file *m, void *v) |
105 | __releases(kernel_lock) |
106 | { |
107 | unlock_kernel(); |
108 | } |
109 | |
110 | static int config_show(struct seq_file *m, void *v) |
111 | { |
112 | struct wan_device *p = v; |
113 | if (v == SEQ_START_TOKEN) { |
114 | seq_puts(m, "Device name | port |IRQ|DMA| mem.addr |" |
115 | "mem.size|option1|option2|option3|option4\n"); |
116 | return 0; |
117 | } |
118 | if (!p->state) |
119 | return 0; |
120 | seq_printf(m, "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n", |
121 | p->name, p->ioport, p->irq, p->dma, p->maddr, p->msize, |
122 | p->hw_opt[0], p->hw_opt[1], p->hw_opt[2], p->hw_opt[3]); |
123 | return 0; |
124 | } |
125 | |
126 | static int status_show(struct seq_file *m, void *v) |
127 | { |
128 | struct wan_device *p = v; |
129 | if (v == SEQ_START_TOKEN) { |
130 | seq_puts(m, "Device name |protocol|station|interface|" |
131 | "clocking|baud rate| MTU |ndev|link state\n"); |
132 | return 0; |
133 | } |
134 | if (!p->state) |
135 | return 0; |
136 | seq_printf(m, "%-15s|%-8s| %-7s| %-9s|%-8s|%9u|%5u|%3u |", |
137 | p->name, |
138 | PROT_DECODE(p->config_id), |
139 | p->config_id == WANCONFIG_FR ? |
140 | (p->station ? "Node" : "CPE") : |
141 | (p->config_id == WANCONFIG_X25 ? |
142 | (p->station ? "DCE" : "DTE") : |
143 | ("N/A")), |
144 | p->interface ? "V.35" : "RS-232", |
145 | p->clocking ? "internal" : "external", |
146 | p->bps, |
147 | p->mtu, |
148 | p->ndev); |
149 | |
150 | switch (p->state) { |
151 | case WAN_UNCONFIGURED: |
152 | seq_printf(m, "%-12s\n", "unconfigured"); |
153 | break; |
154 | case WAN_DISCONNECTED: |
155 | seq_printf(m, "%-12s\n", "disconnected"); |
156 | break; |
157 | case WAN_CONNECTING: |
158 | seq_printf(m, "%-12s\n", "connecting"); |
159 | break; |
160 | case WAN_CONNECTED: |
161 | seq_printf(m, "%-12s\n", "connected"); |
162 | break; |
163 | default: |
164 | seq_printf(m, "%-12s\n", "invalid"); |
165 | break; |
166 | } |
167 | return 0; |
168 | } |
169 | |
170 | static const struct seq_operations config_op = { |
171 | .start = r_start, |
172 | .next = r_next, |
173 | .stop = r_stop, |
174 | .show = config_show, |
175 | }; |
176 | |
177 | static const struct seq_operations status_op = { |
178 | .start = r_start, |
179 | .next = r_next, |
180 | .stop = r_stop, |
181 | .show = status_show, |
182 | }; |
183 | |
184 | static int config_open(struct inode *inode, struct file *file) |
185 | { |
186 | return seq_open(file, &config_op); |
187 | } |
188 | |
189 | static int status_open(struct inode *inode, struct file *file) |
190 | { |
191 | return seq_open(file, &status_op); |
192 | } |
193 | |
194 | static const struct file_operations config_fops = { |
195 | .owner = THIS_MODULE, |
196 | .open = config_open, |
197 | .read = seq_read, |
198 | .llseek = seq_lseek, |
199 | .release = seq_release, |
200 | }; |
201 | |
202 | static const struct file_operations status_fops = { |
203 | .owner = THIS_MODULE, |
204 | .open = status_open, |
205 | .read = seq_read, |
206 | .llseek = seq_lseek, |
207 | .release = seq_release, |
208 | }; |
209 | |
210 | static int wandev_show(struct seq_file *m, void *v) |
211 | { |
212 | struct wan_device *wandev = m->private; |
213 | |
214 | if (wandev->magic != ROUTER_MAGIC) |
215 | return 0; |
216 | |
217 | if (!wandev->state) { |
218 | seq_puts(m, "device is not configured!\n"); |
219 | return 0; |
220 | } |
221 | |
222 | /* Update device statistics */ |
223 | if (wandev->update) { |
224 | int err = wandev->update(wandev); |
225 | if (err == -EAGAIN) { |
226 | seq_puts(m, "Device is busy!\n"); |
227 | return 0; |
228 | } |
229 | if (err) { |
230 | seq_puts(m, "Device is not configured!\n"); |
231 | return 0; |
232 | } |
233 | } |
234 | |
235 | seq_printf(m, PROC_STATS_FORMAT, |
236 | "total packets received", wandev->stats.rx_packets); |
237 | seq_printf(m, PROC_STATS_FORMAT, |
238 | "total packets transmitted", wandev->stats.tx_packets); |
239 | seq_printf(m, PROC_STATS_FORMAT, |
240 | "total bytes received", wandev->stats.rx_bytes); |
241 | seq_printf(m, PROC_STATS_FORMAT, |
242 | "total bytes transmitted", wandev->stats.tx_bytes); |
243 | seq_printf(m, PROC_STATS_FORMAT, |
244 | "bad packets received", wandev->stats.rx_errors); |
245 | seq_printf(m, PROC_STATS_FORMAT, |
246 | "packet transmit problems", wandev->stats.tx_errors); |
247 | seq_printf(m, PROC_STATS_FORMAT, |
248 | "received frames dropped", wandev->stats.rx_dropped); |
249 | seq_printf(m, PROC_STATS_FORMAT, |
250 | "transmit frames dropped", wandev->stats.tx_dropped); |
251 | seq_printf(m, PROC_STATS_FORMAT, |
252 | "multicast packets received", wandev->stats.multicast); |
253 | seq_printf(m, PROC_STATS_FORMAT, |
254 | "transmit collisions", wandev->stats.collisions); |
255 | seq_printf(m, PROC_STATS_FORMAT, |
256 | "receive length errors", wandev->stats.rx_length_errors); |
257 | seq_printf(m, PROC_STATS_FORMAT, |
258 | "receiver overrun errors", wandev->stats.rx_over_errors); |
259 | seq_printf(m, PROC_STATS_FORMAT, |
260 | "CRC errors", wandev->stats.rx_crc_errors); |
261 | seq_printf(m, PROC_STATS_FORMAT, |
262 | "frame format errors (aborts)", wandev->stats.rx_frame_errors); |
263 | seq_printf(m, PROC_STATS_FORMAT, |
264 | "receiver fifo overrun", wandev->stats.rx_fifo_errors); |
265 | seq_printf(m, PROC_STATS_FORMAT, |
266 | "receiver missed packet", wandev->stats.rx_missed_errors); |
267 | seq_printf(m, PROC_STATS_FORMAT, |
268 | "aborted frames transmitted", wandev->stats.tx_aborted_errors); |
269 | return 0; |
270 | } |
271 | |
272 | static int wandev_open(struct inode *inode, struct file *file) |
273 | { |
274 | return single_open(file, wandev_show, PDE(inode)->data); |
275 | } |
276 | |
277 | static const struct file_operations wandev_fops = { |
278 | .owner = THIS_MODULE, |
279 | .open = wandev_open, |
280 | .read = seq_read, |
281 | .llseek = seq_lseek, |
282 | .release = single_release, |
283 | .unlocked_ioctl = wanrouter_ioctl, |
284 | }; |
285 | |
286 | /* |
287 | * Initialize router proc interface. |
288 | */ |
289 | |
290 | int __init wanrouter_proc_init(void) |
291 | { |
292 | struct proc_dir_entry *p; |
293 | proc_router = proc_mkdir(ROUTER_NAME, init_net.proc_net); |
294 | if (!proc_router) |
295 | goto fail; |
296 | |
297 | p = proc_create("config", S_IRUGO, proc_router, &config_fops); |
298 | if (!p) |
299 | goto fail_config; |
300 | p = proc_create("status", S_IRUGO, proc_router, &status_fops); |
301 | if (!p) |
302 | goto fail_stat; |
303 | return 0; |
304 | fail_stat: |
305 | remove_proc_entry("config", proc_router); |
306 | fail_config: |
307 | remove_proc_entry(ROUTER_NAME, init_net.proc_net); |
308 | fail: |
309 | return -ENOMEM; |
310 | } |
311 | |
312 | /* |
313 | * Clean up router proc interface. |
314 | */ |
315 | |
316 | void wanrouter_proc_cleanup(void) |
317 | { |
318 | remove_proc_entry("config", proc_router); |
319 | remove_proc_entry("status", proc_router); |
320 | remove_proc_entry(ROUTER_NAME, init_net.proc_net); |
321 | } |
322 | |
323 | /* |
324 | * Add directory entry for WAN device. |
325 | */ |
326 | |
327 | int wanrouter_proc_add(struct wan_device* wandev) |
328 | { |
329 | if (wandev->magic != ROUTER_MAGIC) |
330 | return -EINVAL; |
331 | |
332 | wandev->dent = proc_create(wandev->name, S_IRUGO, |
333 | proc_router, &wandev_fops); |
334 | if (!wandev->dent) |
335 | return -ENOMEM; |
336 | wandev->dent->data = wandev; |
337 | return 0; |
338 | } |
339 | |
340 | /* |
341 | * Delete directory entry for WAN device. |
342 | */ |
343 | int wanrouter_proc_delete(struct wan_device* wandev) |
344 | { |
345 | if (wandev->magic != ROUTER_MAGIC) |
346 | return -EINVAL; |
347 | remove_proc_entry(wandev->name, proc_router); |
348 | return 0; |
349 | } |
350 | |
351 | #else |
352 | |
353 | /* |
354 | * No /proc - output stubs |
355 | */ |
356 | |
357 | int __init wanrouter_proc_init(void) |
358 | { |
359 | return 0; |
360 | } |
361 | |
362 | void wanrouter_proc_cleanup(void) |
363 | { |
364 | } |
365 | |
366 | int wanrouter_proc_add(struct wan_device *wandev) |
367 | { |
368 | return 0; |
369 | } |
370 | |
371 | int wanrouter_proc_delete(struct wan_device *wandev) |
372 | { |
373 | return 0; |
374 | } |
375 | |
376 | #endif |
377 | |
378 | /* |
379 | * End |
380 | */ |
381 | |
382 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9