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