xref: /openbmc/linux/net/x25/x25_proc.c (revision b6dcefde)
1 /*
2  *	X.25 Packet Layer release 002
3  *
4  *	This is ALPHA test software. This code may break your machine,
5  *	randomly fail to work with new releases, misbehave and/or generally
6  *	screw up. It might even work.
7  *
8  *	This code REQUIRES 2.4 with seq_file support
9  *
10  *	This module:
11  *		This module 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  *	History
17  *	2002/10/06	Arnaldo Carvalho de Melo  seq_file support
18  */
19 
20 #include <linux/init.h>
21 #include <linux/proc_fs.h>
22 #include <linux/seq_file.h>
23 #include <net/net_namespace.h>
24 #include <net/sock.h>
25 #include <net/x25.h>
26 
27 #ifdef CONFIG_PROC_FS
28 static __inline__ struct x25_route *x25_get_route_idx(loff_t pos)
29 {
30 	struct list_head *route_entry;
31 	struct x25_route *rt = NULL;
32 
33 	list_for_each(route_entry, &x25_route_list) {
34 		rt = list_entry(route_entry, struct x25_route, node);
35 		if (!pos--)
36 			goto found;
37 	}
38 	rt = NULL;
39 found:
40 	return rt;
41 }
42 
43 static void *x25_seq_route_start(struct seq_file *seq, loff_t *pos)
44 	__acquires(x25_route_list_lock)
45 {
46 	loff_t l = *pos;
47 
48 	read_lock_bh(&x25_route_list_lock);
49 	return l ? x25_get_route_idx(--l) : SEQ_START_TOKEN;
50 }
51 
52 static void *x25_seq_route_next(struct seq_file *seq, void *v, loff_t *pos)
53 {
54 	struct x25_route *rt;
55 
56 	++*pos;
57 	if (v == SEQ_START_TOKEN) {
58 		rt = NULL;
59 		if (!list_empty(&x25_route_list))
60 			rt = list_entry(x25_route_list.next,
61 					struct x25_route, node);
62 		goto out;
63 	}
64 	rt = v;
65 	if (rt->node.next != &x25_route_list)
66 		rt = list_entry(rt->node.next, struct x25_route, node);
67 	else
68 		rt = NULL;
69 out:
70 	return rt;
71 }
72 
73 static void x25_seq_route_stop(struct seq_file *seq, void *v)
74 	__releases(x25_route_list_lock)
75 {
76 	read_unlock_bh(&x25_route_list_lock);
77 }
78 
79 static int x25_seq_route_show(struct seq_file *seq, void *v)
80 {
81 	struct x25_route *rt;
82 
83 	if (v == SEQ_START_TOKEN) {
84 		seq_puts(seq, "Address          Digits  Device\n");
85 		goto out;
86 	}
87 
88 	rt = v;
89 	seq_printf(seq, "%-15s  %-6d  %-5s\n",
90 		   rt->address.x25_addr, rt->sigdigits,
91 		   rt->dev ? rt->dev->name : "???");
92 out:
93 	return 0;
94 }
95 
96 static __inline__ struct sock *x25_get_socket_idx(loff_t pos)
97 {
98 	struct sock *s;
99 	struct hlist_node *node;
100 
101 	sk_for_each(s, node, &x25_list)
102 		if (!pos--)
103 			goto found;
104 	s = NULL;
105 found:
106 	return s;
107 }
108 
109 static void *x25_seq_socket_start(struct seq_file *seq, loff_t *pos)
110 	__acquires(x25_list_lock)
111 {
112 	loff_t l = *pos;
113 
114 	read_lock_bh(&x25_list_lock);
115 	return l ? x25_get_socket_idx(--l) : SEQ_START_TOKEN;
116 }
117 
118 static void *x25_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos)
119 {
120 	struct sock *s;
121 
122 	++*pos;
123 	if (v == SEQ_START_TOKEN) {
124 		s = sk_head(&x25_list);
125 		goto out;
126 	}
127 	s = sk_next(v);
128 out:
129 	return s;
130 }
131 
132 static void x25_seq_socket_stop(struct seq_file *seq, void *v)
133 	__releases(x25_list_lock)
134 {
135 	read_unlock_bh(&x25_list_lock);
136 }
137 
138 static int x25_seq_socket_show(struct seq_file *seq, void *v)
139 {
140 	struct sock *s;
141 	struct x25_sock *x25;
142 	struct net_device *dev;
143 	const char *devname;
144 
145 	if (v == SEQ_START_TOKEN) {
146 		seq_printf(seq, "dest_addr  src_addr   dev   lci st vs vr "
147 				"va   t  t2 t21 t22 t23 Snd-Q Rcv-Q inode\n");
148 		goto out;
149 	}
150 
151 	s = v;
152 	x25 = x25_sk(s);
153 
154 	if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL)
155 		devname = "???";
156 	else
157 		devname = x25->neighbour->dev->name;
158 
159 	seq_printf(seq, "%-10s %-10s %-5s %3.3X  %d  %d  %d  %d %3lu %3lu "
160 			"%3lu %3lu %3lu %5d %5d %ld\n",
161 		   !x25->dest_addr.x25_addr[0] ? "*" : x25->dest_addr.x25_addr,
162 		   !x25->source_addr.x25_addr[0] ? "*" : x25->source_addr.x25_addr,
163 		   devname, x25->lci & 0x0FFF, x25->state, x25->vs, x25->vr,
164 		   x25->va, x25_display_timer(s) / HZ, x25->t2  / HZ,
165 		   x25->t21 / HZ, x25->t22 / HZ, x25->t23 / HZ,
166 		   sk_wmem_alloc_get(s),
167 		   sk_rmem_alloc_get(s),
168 		   s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L);
169 out:
170 	return 0;
171 }
172 
173 static __inline__ struct x25_forward *x25_get_forward_idx(loff_t pos)
174 {
175 	struct x25_forward *f;
176 	struct list_head *entry;
177 
178 	list_for_each(entry, &x25_forward_list) {
179 		f = list_entry(entry, struct x25_forward, node);
180 		if (!pos--)
181 			goto found;
182 	}
183 
184 	f = NULL;
185 found:
186 	return f;
187 }
188 
189 static void *x25_seq_forward_start(struct seq_file *seq, loff_t *pos)
190 	__acquires(x25_forward_list_lock)
191 {
192 	loff_t l = *pos;
193 
194 	read_lock_bh(&x25_forward_list_lock);
195 	return l ? x25_get_forward_idx(--l) : SEQ_START_TOKEN;
196 }
197 
198 static void *x25_seq_forward_next(struct seq_file *seq, void *v, loff_t *pos)
199 {
200 	struct x25_forward *f;
201 
202 	++*pos;
203 	if (v == SEQ_START_TOKEN) {
204 		f = NULL;
205 		if (!list_empty(&x25_forward_list))
206 			f = list_entry(x25_forward_list.next,
207 					struct x25_forward, node);
208 		goto out;
209 	}
210 	f = v;
211 	if (f->node.next != &x25_forward_list)
212 		f = list_entry(f->node.next, struct x25_forward, node);
213 	else
214 		f = NULL;
215 out:
216 	return f;
217 
218 }
219 
220 static void x25_seq_forward_stop(struct seq_file *seq, void *v)
221 	__releases(x25_forward_list_lock)
222 {
223 	read_unlock_bh(&x25_forward_list_lock);
224 }
225 
226 static int x25_seq_forward_show(struct seq_file *seq, void *v)
227 {
228 	struct x25_forward *f;
229 
230 	if (v == SEQ_START_TOKEN) {
231 		seq_printf(seq, "lci dev1       dev2\n");
232 		goto out;
233 	}
234 
235 	f = v;
236 
237 	seq_printf(seq, "%d %-10s %-10s\n",
238 			f->lci, f->dev1->name, f->dev2->name);
239 
240 out:
241 	return 0;
242 }
243 
244 static const struct seq_operations x25_seq_route_ops = {
245 	.start  = x25_seq_route_start,
246 	.next   = x25_seq_route_next,
247 	.stop   = x25_seq_route_stop,
248 	.show   = x25_seq_route_show,
249 };
250 
251 static const struct seq_operations x25_seq_socket_ops = {
252 	.start  = x25_seq_socket_start,
253 	.next   = x25_seq_socket_next,
254 	.stop   = x25_seq_socket_stop,
255 	.show   = x25_seq_socket_show,
256 };
257 
258 static const struct seq_operations x25_seq_forward_ops = {
259 	.start  = x25_seq_forward_start,
260 	.next   = x25_seq_forward_next,
261 	.stop   = x25_seq_forward_stop,
262 	.show   = x25_seq_forward_show,
263 };
264 
265 static int x25_seq_socket_open(struct inode *inode, struct file *file)
266 {
267 	return seq_open(file, &x25_seq_socket_ops);
268 }
269 
270 static int x25_seq_route_open(struct inode *inode, struct file *file)
271 {
272 	return seq_open(file, &x25_seq_route_ops);
273 }
274 
275 static int x25_seq_forward_open(struct inode *inode, struct file *file)
276 {
277 	return seq_open(file, &x25_seq_forward_ops);
278 }
279 
280 static const struct file_operations x25_seq_socket_fops = {
281 	.owner		= THIS_MODULE,
282 	.open		= x25_seq_socket_open,
283 	.read		= seq_read,
284 	.llseek		= seq_lseek,
285 	.release	= seq_release,
286 };
287 
288 static const struct file_operations x25_seq_route_fops = {
289 	.owner		= THIS_MODULE,
290 	.open		= x25_seq_route_open,
291 	.read		= seq_read,
292 	.llseek		= seq_lseek,
293 	.release	= seq_release,
294 };
295 
296 static const struct file_operations x25_seq_forward_fops = {
297 	.owner		= THIS_MODULE,
298 	.open		= x25_seq_forward_open,
299 	.read		= seq_read,
300 	.llseek		= seq_lseek,
301 	.release	= seq_release,
302 };
303 
304 static struct proc_dir_entry *x25_proc_dir;
305 
306 int __init x25_proc_init(void)
307 {
308 	struct proc_dir_entry *p;
309 	int rc = -ENOMEM;
310 
311 	x25_proc_dir = proc_mkdir("x25", init_net.proc_net);
312 	if (!x25_proc_dir)
313 		goto out;
314 
315 	p = proc_create("route", S_IRUGO, x25_proc_dir, &x25_seq_route_fops);
316 	if (!p)
317 		goto out_route;
318 
319 	p = proc_create("socket", S_IRUGO, x25_proc_dir, &x25_seq_socket_fops);
320 	if (!p)
321 		goto out_socket;
322 
323 	p = proc_create("forward", S_IRUGO, x25_proc_dir,
324 			&x25_seq_forward_fops);
325 	if (!p)
326 		goto out_forward;
327 	rc = 0;
328 
329 out:
330 	return rc;
331 out_forward:
332 	remove_proc_entry("socket", x25_proc_dir);
333 out_socket:
334 	remove_proc_entry("route", x25_proc_dir);
335 out_route:
336 	remove_proc_entry("x25", init_net.proc_net);
337 	goto out;
338 }
339 
340 void __exit x25_proc_exit(void)
341 {
342 	remove_proc_entry("forward", x25_proc_dir);
343 	remove_proc_entry("route", x25_proc_dir);
344 	remove_proc_entry("socket", x25_proc_dir);
345 	remove_proc_entry("x25", init_net.proc_net);
346 }
347 
348 #else /* CONFIG_PROC_FS */
349 
350 int __init x25_proc_init(void)
351 {
352 	return 0;
353 }
354 
355 void __exit x25_proc_exit(void)
356 {
357 }
358 #endif /* CONFIG_PROC_FS */
359