xref: /openbmc/linux/net/rxrpc/proc.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1 /* proc.c: /proc interface for RxRPC
2  *
3  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11 
12 #include <linux/sched.h>
13 #include <linux/slab.h>
14 #include <linux/module.h>
15 #include <linux/proc_fs.h>
16 #include <linux/seq_file.h>
17 #include <rxrpc/rxrpc.h>
18 #include <rxrpc/transport.h>
19 #include <rxrpc/peer.h>
20 #include <rxrpc/connection.h>
21 #include <rxrpc/call.h>
22 #include <rxrpc/message.h>
23 #include "internal.h"
24 
25 static struct proc_dir_entry *proc_rxrpc;
26 
27 static int rxrpc_proc_transports_open(struct inode *inode, struct file *file);
28 static void *rxrpc_proc_transports_start(struct seq_file *p, loff_t *pos);
29 static void *rxrpc_proc_transports_next(struct seq_file *p, void *v, loff_t *pos);
30 static void rxrpc_proc_transports_stop(struct seq_file *p, void *v);
31 static int rxrpc_proc_transports_show(struct seq_file *m, void *v);
32 
33 static struct seq_operations rxrpc_proc_transports_ops = {
34 	.start	= rxrpc_proc_transports_start,
35 	.next	= rxrpc_proc_transports_next,
36 	.stop	= rxrpc_proc_transports_stop,
37 	.show	= rxrpc_proc_transports_show,
38 };
39 
40 static struct file_operations rxrpc_proc_transports_fops = {
41 	.open		= rxrpc_proc_transports_open,
42 	.read		= seq_read,
43 	.llseek		= seq_lseek,
44 	.release	= seq_release,
45 };
46 
47 static int rxrpc_proc_peers_open(struct inode *inode, struct file *file);
48 static void *rxrpc_proc_peers_start(struct seq_file *p, loff_t *pos);
49 static void *rxrpc_proc_peers_next(struct seq_file *p, void *v, loff_t *pos);
50 static void rxrpc_proc_peers_stop(struct seq_file *p, void *v);
51 static int rxrpc_proc_peers_show(struct seq_file *m, void *v);
52 
53 static struct seq_operations rxrpc_proc_peers_ops = {
54 	.start	= rxrpc_proc_peers_start,
55 	.next	= rxrpc_proc_peers_next,
56 	.stop	= rxrpc_proc_peers_stop,
57 	.show	= rxrpc_proc_peers_show,
58 };
59 
60 static struct file_operations rxrpc_proc_peers_fops = {
61 	.open		= rxrpc_proc_peers_open,
62 	.read		= seq_read,
63 	.llseek		= seq_lseek,
64 	.release	= seq_release,
65 };
66 
67 static int rxrpc_proc_conns_open(struct inode *inode, struct file *file);
68 static void *rxrpc_proc_conns_start(struct seq_file *p, loff_t *pos);
69 static void *rxrpc_proc_conns_next(struct seq_file *p, void *v, loff_t *pos);
70 static void rxrpc_proc_conns_stop(struct seq_file *p, void *v);
71 static int rxrpc_proc_conns_show(struct seq_file *m, void *v);
72 
73 static struct seq_operations rxrpc_proc_conns_ops = {
74 	.start	= rxrpc_proc_conns_start,
75 	.next	= rxrpc_proc_conns_next,
76 	.stop	= rxrpc_proc_conns_stop,
77 	.show	= rxrpc_proc_conns_show,
78 };
79 
80 static struct file_operations rxrpc_proc_conns_fops = {
81 	.open		= rxrpc_proc_conns_open,
82 	.read		= seq_read,
83 	.llseek		= seq_lseek,
84 	.release	= seq_release,
85 };
86 
87 static int rxrpc_proc_calls_open(struct inode *inode, struct file *file);
88 static void *rxrpc_proc_calls_start(struct seq_file *p, loff_t *pos);
89 static void *rxrpc_proc_calls_next(struct seq_file *p, void *v, loff_t *pos);
90 static void rxrpc_proc_calls_stop(struct seq_file *p, void *v);
91 static int rxrpc_proc_calls_show(struct seq_file *m, void *v);
92 
93 static struct seq_operations rxrpc_proc_calls_ops = {
94 	.start	= rxrpc_proc_calls_start,
95 	.next	= rxrpc_proc_calls_next,
96 	.stop	= rxrpc_proc_calls_stop,
97 	.show	= rxrpc_proc_calls_show,
98 };
99 
100 static struct file_operations rxrpc_proc_calls_fops = {
101 	.open		= rxrpc_proc_calls_open,
102 	.read		= seq_read,
103 	.llseek		= seq_lseek,
104 	.release	= seq_release,
105 };
106 
107 static const char *rxrpc_call_states7[] = {
108 	"complet",
109 	"error  ",
110 	"rcv_op ",
111 	"rcv_arg",
112 	"got_arg",
113 	"snd_rpl",
114 	"fin_ack",
115 	"snd_arg",
116 	"rcv_rpl",
117 	"got_rpl"
118 };
119 
120 static const char *rxrpc_call_error_states7[] = {
121 	"no_err ",
122 	"loc_abt",
123 	"rmt_abt",
124 	"loc_err",
125 	"rmt_err"
126 };
127 
128 /*****************************************************************************/
129 /*
130  * initialise the /proc/net/rxrpc/ directory
131  */
132 int rxrpc_proc_init(void)
133 {
134 	struct proc_dir_entry *p;
135 
136 	proc_rxrpc = proc_mkdir("rxrpc", proc_net);
137 	if (!proc_rxrpc)
138 		goto error;
139 	proc_rxrpc->owner = THIS_MODULE;
140 
141 	p = create_proc_entry("calls", 0, proc_rxrpc);
142 	if (!p)
143 		goto error_proc;
144 	p->proc_fops = &rxrpc_proc_calls_fops;
145 	p->owner = THIS_MODULE;
146 
147 	p = create_proc_entry("connections", 0, proc_rxrpc);
148 	if (!p)
149 		goto error_calls;
150 	p->proc_fops = &rxrpc_proc_conns_fops;
151 	p->owner = THIS_MODULE;
152 
153 	p = create_proc_entry("peers", 0, proc_rxrpc);
154 	if (!p)
155 		goto error_calls;
156 	p->proc_fops = &rxrpc_proc_peers_fops;
157 	p->owner = THIS_MODULE;
158 
159 	p = create_proc_entry("transports", 0, proc_rxrpc);
160 	if (!p)
161 		goto error_conns;
162 	p->proc_fops = &rxrpc_proc_transports_fops;
163 	p->owner = THIS_MODULE;
164 
165 	return 0;
166 
167  error_conns:
168 	remove_proc_entry("connections", proc_rxrpc);
169  error_calls:
170 	remove_proc_entry("calls", proc_rxrpc);
171  error_proc:
172 	remove_proc_entry("rxrpc", proc_net);
173  error:
174 	return -ENOMEM;
175 } /* end rxrpc_proc_init() */
176 
177 /*****************************************************************************/
178 /*
179  * clean up the /proc/net/rxrpc/ directory
180  */
181 void rxrpc_proc_cleanup(void)
182 {
183 	remove_proc_entry("transports", proc_rxrpc);
184 	remove_proc_entry("peers", proc_rxrpc);
185 	remove_proc_entry("connections", proc_rxrpc);
186 	remove_proc_entry("calls", proc_rxrpc);
187 
188 	remove_proc_entry("rxrpc", proc_net);
189 
190 } /* end rxrpc_proc_cleanup() */
191 
192 /*****************************************************************************/
193 /*
194  * open "/proc/net/rxrpc/transports" which provides a summary of extant transports
195  */
196 static int rxrpc_proc_transports_open(struct inode *inode, struct file *file)
197 {
198 	struct seq_file *m;
199 	int ret;
200 
201 	ret = seq_open(file, &rxrpc_proc_transports_ops);
202 	if (ret < 0)
203 		return ret;
204 
205 	m = file->private_data;
206 	m->private = PDE(inode)->data;
207 
208 	return 0;
209 } /* end rxrpc_proc_transports_open() */
210 
211 /*****************************************************************************/
212 /*
213  * set up the iterator to start reading from the transports list and return the first item
214  */
215 static void *rxrpc_proc_transports_start(struct seq_file *m, loff_t *_pos)
216 {
217 	struct list_head *_p;
218 	loff_t pos = *_pos;
219 
220 	/* lock the list against modification */
221 	down_read(&rxrpc_proc_transports_sem);
222 
223 	/* allow for the header line */
224 	if (!pos)
225 		return SEQ_START_TOKEN;
226 	pos--;
227 
228 	/* find the n'th element in the list */
229 	list_for_each(_p, &rxrpc_proc_transports)
230 		if (!pos--)
231 			break;
232 
233 	return _p != &rxrpc_proc_transports ? _p : NULL;
234 } /* end rxrpc_proc_transports_start() */
235 
236 /*****************************************************************************/
237 /*
238  * move to next call in transports list
239  */
240 static void *rxrpc_proc_transports_next(struct seq_file *p, void *v, loff_t *pos)
241 {
242 	struct list_head *_p;
243 
244 	(*pos)++;
245 
246 	_p = v;
247 	_p = (v == SEQ_START_TOKEN) ? rxrpc_proc_transports.next : _p->next;
248 
249 	return _p != &rxrpc_proc_transports ? _p : NULL;
250 } /* end rxrpc_proc_transports_next() */
251 
252 /*****************************************************************************/
253 /*
254  * clean up after reading from the transports list
255  */
256 static void rxrpc_proc_transports_stop(struct seq_file *p, void *v)
257 {
258 	up_read(&rxrpc_proc_transports_sem);
259 
260 } /* end rxrpc_proc_transports_stop() */
261 
262 /*****************************************************************************/
263 /*
264  * display a header line followed by a load of call lines
265  */
266 static int rxrpc_proc_transports_show(struct seq_file *m, void *v)
267 {
268 	struct rxrpc_transport *trans =
269 		list_entry(v, struct rxrpc_transport, proc_link);
270 
271 	/* display header on line 1 */
272 	if (v == SEQ_START_TOKEN) {
273 		seq_puts(m, "LOCAL USE\n");
274 		return 0;
275 	}
276 
277 	/* display one transport per line on subsequent lines */
278 	seq_printf(m, "%5hu %3d\n",
279 		   trans->port,
280 		   atomic_read(&trans->usage)
281 		   );
282 
283 	return 0;
284 } /* end rxrpc_proc_transports_show() */
285 
286 /*****************************************************************************/
287 /*
288  * open "/proc/net/rxrpc/peers" which provides a summary of extant peers
289  */
290 static int rxrpc_proc_peers_open(struct inode *inode, struct file *file)
291 {
292 	struct seq_file *m;
293 	int ret;
294 
295 	ret = seq_open(file, &rxrpc_proc_peers_ops);
296 	if (ret < 0)
297 		return ret;
298 
299 	m = file->private_data;
300 	m->private = PDE(inode)->data;
301 
302 	return 0;
303 } /* end rxrpc_proc_peers_open() */
304 
305 /*****************************************************************************/
306 /*
307  * set up the iterator to start reading from the peers list and return the
308  * first item
309  */
310 static void *rxrpc_proc_peers_start(struct seq_file *m, loff_t *_pos)
311 {
312 	struct list_head *_p;
313 	loff_t pos = *_pos;
314 
315 	/* lock the list against modification */
316 	down_read(&rxrpc_peers_sem);
317 
318 	/* allow for the header line */
319 	if (!pos)
320 		return SEQ_START_TOKEN;
321 	pos--;
322 
323 	/* find the n'th element in the list */
324 	list_for_each(_p, &rxrpc_peers)
325 		if (!pos--)
326 			break;
327 
328 	return _p != &rxrpc_peers ? _p : NULL;
329 } /* end rxrpc_proc_peers_start() */
330 
331 /*****************************************************************************/
332 /*
333  * move to next conn in peers list
334  */
335 static void *rxrpc_proc_peers_next(struct seq_file *p, void *v, loff_t *pos)
336 {
337 	struct list_head *_p;
338 
339 	(*pos)++;
340 
341 	_p = v;
342 	_p = (v == SEQ_START_TOKEN) ? rxrpc_peers.next : _p->next;
343 
344 	return _p != &rxrpc_peers ? _p : NULL;
345 } /* end rxrpc_proc_peers_next() */
346 
347 /*****************************************************************************/
348 /*
349  * clean up after reading from the peers list
350  */
351 static void rxrpc_proc_peers_stop(struct seq_file *p, void *v)
352 {
353 	up_read(&rxrpc_peers_sem);
354 
355 } /* end rxrpc_proc_peers_stop() */
356 
357 /*****************************************************************************/
358 /*
359  * display a header line followed by a load of conn lines
360  */
361 static int rxrpc_proc_peers_show(struct seq_file *m, void *v)
362 {
363 	struct rxrpc_peer *peer = list_entry(v, struct rxrpc_peer, proc_link);
364 	signed long timeout;
365 
366 	/* display header on line 1 */
367 	if (v == SEQ_START_TOKEN) {
368 		seq_puts(m, "LOCAL REMOTE   USAGE CONNS  TIMEOUT"
369 			 "   MTU RTT(uS)\n");
370 		return 0;
371 	}
372 
373 	/* display one peer per line on subsequent lines */
374 	timeout = 0;
375 	if (!list_empty(&peer->timeout.link))
376 		timeout = (signed long) peer->timeout.timo_jif -
377 			(signed long) jiffies;
378 
379 	seq_printf(m, "%5hu %08x %5d %5d %8ld %5Zu %7lu\n",
380 		   peer->trans->port,
381 		   ntohl(peer->addr.s_addr),
382 		   atomic_read(&peer->usage),
383 		   atomic_read(&peer->conn_count),
384 		   timeout,
385 		   peer->if_mtu,
386 		   (long) peer->rtt
387 		   );
388 
389 	return 0;
390 } /* end rxrpc_proc_peers_show() */
391 
392 /*****************************************************************************/
393 /*
394  * open "/proc/net/rxrpc/connections" which provides a summary of extant
395  * connections
396  */
397 static int rxrpc_proc_conns_open(struct inode *inode, struct file *file)
398 {
399 	struct seq_file *m;
400 	int ret;
401 
402 	ret = seq_open(file, &rxrpc_proc_conns_ops);
403 	if (ret < 0)
404 		return ret;
405 
406 	m = file->private_data;
407 	m->private = PDE(inode)->data;
408 
409 	return 0;
410 } /* end rxrpc_proc_conns_open() */
411 
412 /*****************************************************************************/
413 /*
414  * set up the iterator to start reading from the conns list and return the
415  * first item
416  */
417 static void *rxrpc_proc_conns_start(struct seq_file *m, loff_t *_pos)
418 {
419 	struct list_head *_p;
420 	loff_t pos = *_pos;
421 
422 	/* lock the list against modification */
423 	down_read(&rxrpc_conns_sem);
424 
425 	/* allow for the header line */
426 	if (!pos)
427 		return SEQ_START_TOKEN;
428 	pos--;
429 
430 	/* find the n'th element in the list */
431 	list_for_each(_p, &rxrpc_conns)
432 		if (!pos--)
433 			break;
434 
435 	return _p != &rxrpc_conns ? _p : NULL;
436 } /* end rxrpc_proc_conns_start() */
437 
438 /*****************************************************************************/
439 /*
440  * move to next conn in conns list
441  */
442 static void *rxrpc_proc_conns_next(struct seq_file *p, void *v, loff_t *pos)
443 {
444 	struct list_head *_p;
445 
446 	(*pos)++;
447 
448 	_p = v;
449 	_p = (v == SEQ_START_TOKEN) ? rxrpc_conns.next : _p->next;
450 
451 	return _p != &rxrpc_conns ? _p : NULL;
452 } /* end rxrpc_proc_conns_next() */
453 
454 /*****************************************************************************/
455 /*
456  * clean up after reading from the conns list
457  */
458 static void rxrpc_proc_conns_stop(struct seq_file *p, void *v)
459 {
460 	up_read(&rxrpc_conns_sem);
461 
462 } /* end rxrpc_proc_conns_stop() */
463 
464 /*****************************************************************************/
465 /*
466  * display a header line followed by a load of conn lines
467  */
468 static int rxrpc_proc_conns_show(struct seq_file *m, void *v)
469 {
470 	struct rxrpc_connection *conn;
471 	signed long timeout;
472 
473 	conn = list_entry(v, struct rxrpc_connection, proc_link);
474 
475 	/* display header on line 1 */
476 	if (v == SEQ_START_TOKEN) {
477 		seq_puts(m,
478 			 "LOCAL REMOTE   RPORT SRVC CONN     END SERIALNO "
479 			 "CALLNO     MTU  TIMEOUT"
480 			 "\n");
481 		return 0;
482 	}
483 
484 	/* display one conn per line on subsequent lines */
485 	timeout = 0;
486 	if (!list_empty(&conn->timeout.link))
487 		timeout = (signed long) conn->timeout.timo_jif -
488 			(signed long) jiffies;
489 
490 	seq_printf(m,
491 		   "%5hu %08x %5hu %04hx %08x %-3.3s %08x %08x %5Zu %8ld\n",
492 		   conn->trans->port,
493 		   ntohl(conn->addr.sin_addr.s_addr),
494 		   ntohs(conn->addr.sin_port),
495 		   ntohs(conn->service_id),
496 		   ntohl(conn->conn_id),
497 		   conn->out_clientflag ? "CLT" : "SRV",
498 		   conn->serial_counter,
499 		   conn->call_counter,
500 		   conn->mtu_size,
501 		   timeout
502 		   );
503 
504 	return 0;
505 } /* end rxrpc_proc_conns_show() */
506 
507 /*****************************************************************************/
508 /*
509  * open "/proc/net/rxrpc/calls" which provides a summary of extant calls
510  */
511 static int rxrpc_proc_calls_open(struct inode *inode, struct file *file)
512 {
513 	struct seq_file *m;
514 	int ret;
515 
516 	ret = seq_open(file, &rxrpc_proc_calls_ops);
517 	if (ret < 0)
518 		return ret;
519 
520 	m = file->private_data;
521 	m->private = PDE(inode)->data;
522 
523 	return 0;
524 } /* end rxrpc_proc_calls_open() */
525 
526 /*****************************************************************************/
527 /*
528  * set up the iterator to start reading from the calls list and return the
529  * first item
530  */
531 static void *rxrpc_proc_calls_start(struct seq_file *m, loff_t *_pos)
532 {
533 	struct list_head *_p;
534 	loff_t pos = *_pos;
535 
536 	/* lock the list against modification */
537 	down_read(&rxrpc_calls_sem);
538 
539 	/* allow for the header line */
540 	if (!pos)
541 		return SEQ_START_TOKEN;
542 	pos--;
543 
544 	/* find the n'th element in the list */
545 	list_for_each(_p, &rxrpc_calls)
546 		if (!pos--)
547 			break;
548 
549 	return _p != &rxrpc_calls ? _p : NULL;
550 } /* end rxrpc_proc_calls_start() */
551 
552 /*****************************************************************************/
553 /*
554  * move to next call in calls list
555  */
556 static void *rxrpc_proc_calls_next(struct seq_file *p, void *v, loff_t *pos)
557 {
558 	struct list_head *_p;
559 
560 	(*pos)++;
561 
562 	_p = v;
563 	_p = (v == SEQ_START_TOKEN) ? rxrpc_calls.next : _p->next;
564 
565 	return _p != &rxrpc_calls ? _p : NULL;
566 } /* end rxrpc_proc_calls_next() */
567 
568 /*****************************************************************************/
569 /*
570  * clean up after reading from the calls list
571  */
572 static void rxrpc_proc_calls_stop(struct seq_file *p, void *v)
573 {
574 	up_read(&rxrpc_calls_sem);
575 
576 } /* end rxrpc_proc_calls_stop() */
577 
578 /*****************************************************************************/
579 /*
580  * display a header line followed by a load of call lines
581  */
582 static int rxrpc_proc_calls_show(struct seq_file *m, void *v)
583 {
584 	struct rxrpc_call *call = list_entry(v, struct rxrpc_call, call_link);
585 
586 	/* display header on line 1 */
587 	if (v == SEQ_START_TOKEN) {
588 		seq_puts(m,
589 			 "LOCAL REMOT SRVC CONN     CALL     DIR USE "
590 			 " L STATE   OPCODE ABORT    ERRNO\n"
591 			 );
592 		return 0;
593 	}
594 
595 	/* display one call per line on subsequent lines */
596 	seq_printf(m,
597 		   "%5hu %5hu %04hx %08x %08x %s %3u%c"
598 		   " %c %-7.7s %6d %08x %5d\n",
599 		   call->conn->trans->port,
600 		   ntohs(call->conn->addr.sin_port),
601 		   ntohs(call->conn->service_id),
602 		   ntohl(call->conn->conn_id),
603 		   ntohl(call->call_id),
604 		   call->conn->service ? "SVC" : "CLT",
605 		   atomic_read(&call->usage),
606 		   waitqueue_active(&call->waitq) ? 'w' : ' ',
607 		   call->app_last_rcv ? 'Y' : '-',
608 		   (call->app_call_state!=RXRPC_CSTATE_ERROR ?
609 		    rxrpc_call_states7[call->app_call_state] :
610 		    rxrpc_call_error_states7[call->app_err_state]),
611 		   call->app_opcode,
612 		   call->app_abort_code,
613 		   call->app_errno
614 		   );
615 
616 	return 0;
617 } /* end rxrpc_proc_calls_show() */
618