diff options
Diffstat (limited to 'net/bluetooth/af_bluetooth.c')
-rw-r--r-- | net/bluetooth/af_bluetooth.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index f7db5792ec64..58f9762b339a 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <asm/ioctls.h> | 28 | #include <asm/ioctls.h> |
29 | 29 | ||
30 | #include <net/bluetooth/bluetooth.h> | 30 | #include <net/bluetooth/bluetooth.h> |
31 | #include <linux/proc_fs.h> | ||
31 | 32 | ||
32 | #define VERSION "2.16" | 33 | #define VERSION "2.16" |
33 | 34 | ||
@@ -532,6 +533,146 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo) | |||
532 | } | 533 | } |
533 | EXPORT_SYMBOL(bt_sock_wait_state); | 534 | EXPORT_SYMBOL(bt_sock_wait_state); |
534 | 535 | ||
536 | #ifdef CONFIG_PROC_FS | ||
537 | struct bt_seq_state { | ||
538 | struct bt_sock_list *l; | ||
539 | }; | ||
540 | |||
541 | static void *bt_seq_start(struct seq_file *seq, loff_t *pos) | ||
542 | __acquires(seq->private->l->lock) | ||
543 | { | ||
544 | struct bt_seq_state *s = seq->private; | ||
545 | struct bt_sock_list *l = s->l; | ||
546 | |||
547 | read_lock(&l->lock); | ||
548 | return seq_hlist_start_head(&l->head, *pos); | ||
549 | } | ||
550 | |||
551 | static void *bt_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
552 | { | ||
553 | struct bt_seq_state *s = seq->private; | ||
554 | struct bt_sock_list *l = s->l; | ||
555 | |||
556 | return seq_hlist_next(v, &l->head, pos); | ||
557 | } | ||
558 | |||
559 | static void bt_seq_stop(struct seq_file *seq, void *v) | ||
560 | __releases(seq->private->l->lock) | ||
561 | { | ||
562 | struct bt_seq_state *s = seq->private; | ||
563 | struct bt_sock_list *l = s->l; | ||
564 | |||
565 | read_unlock(&l->lock); | ||
566 | } | ||
567 | |||
568 | static int bt_seq_show(struct seq_file *seq, void *v) | ||
569 | { | ||
570 | struct sock *sk; | ||
571 | struct bt_sock *bt; | ||
572 | struct bt_seq_state *s = seq->private; | ||
573 | struct bt_sock_list *l = s->l; | ||
574 | bdaddr_t src_baswapped, dst_baswapped; | ||
575 | |||
576 | if (v == SEQ_START_TOKEN) { | ||
577 | seq_puts(seq ,"sk RefCnt Rmem Wmem User Inode Src Dst Parent"); | ||
578 | |||
579 | if (l->custom_seq_show) { | ||
580 | seq_putc(seq, ' '); | ||
581 | l->custom_seq_show(seq, v); | ||
582 | } | ||
583 | |||
584 | seq_putc(seq, '\n'); | ||
585 | } else { | ||
586 | sk = sk_entry(v); | ||
587 | bt = bt_sk(sk); | ||
588 | baswap(&src_baswapped, &bt->src); | ||
589 | baswap(&dst_baswapped, &bt->dst); | ||
590 | |||
591 | seq_printf(seq, "%pK %-6d %-6u %-6u %-6u %-6lu %pM %pM %-6lu", | ||
592 | sk, | ||
593 | atomic_read(&sk->sk_refcnt), | ||
594 | sk_rmem_alloc_get(sk), | ||
595 | sk_wmem_alloc_get(sk), | ||
596 | sock_i_uid(sk), | ||
597 | sock_i_ino(sk), | ||
598 | &src_baswapped, | ||
599 | &dst_baswapped, | ||
600 | bt->parent? sock_i_ino(bt->parent): 0LU); | ||
601 | |||
602 | if (l->custom_seq_show) { | ||
603 | seq_putc(seq, ' '); | ||
604 | l->custom_seq_show(seq, v); | ||
605 | } | ||
606 | |||
607 | seq_putc(seq, '\n'); | ||
608 | } | ||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | static struct seq_operations bt_seq_ops = { | ||
613 | .start = bt_seq_start, | ||
614 | .next = bt_seq_next, | ||
615 | .stop = bt_seq_stop, | ||
616 | .show = bt_seq_show, | ||
617 | }; | ||
618 | |||
619 | static int bt_seq_open(struct inode *inode, struct file *file) | ||
620 | { | ||
621 | struct bt_sock_list *sk_list; | ||
622 | struct bt_seq_state *s; | ||
623 | |||
624 | sk_list = PDE(inode)->data; | ||
625 | s = __seq_open_private(file, &bt_seq_ops, | ||
626 | sizeof(struct bt_seq_state)); | ||
627 | if (s == NULL) | ||
628 | return -ENOMEM; | ||
629 | |||
630 | s->l = sk_list; | ||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | int bt_procfs_init(struct module* module, struct net *net, const char *name, | ||
635 | struct bt_sock_list* sk_list, | ||
636 | int (* seq_show)(struct seq_file *, void *)) | ||
637 | { | ||
638 | struct proc_dir_entry * pde; | ||
639 | |||
640 | sk_list->custom_seq_show = seq_show; | ||
641 | |||
642 | sk_list->fops.owner = module; | ||
643 | sk_list->fops.open = bt_seq_open; | ||
644 | sk_list->fops.read = seq_read; | ||
645 | sk_list->fops.llseek = seq_lseek; | ||
646 | sk_list->fops.release = seq_release_private; | ||
647 | |||
648 | pde = proc_net_fops_create(net, name, 0, &sk_list->fops); | ||
649 | if (pde == NULL) | ||
650 | return -ENOMEM; | ||
651 | |||
652 | pde->data = sk_list; | ||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | void bt_procfs_cleanup(struct net *net, const char *name) | ||
658 | { | ||
659 | proc_net_remove(net, name); | ||
660 | } | ||
661 | #else | ||
662 | int bt_procfs_init(struct module* module, struct net *net, const char *name, | ||
663 | struct bt_sock_list* sk_list, | ||
664 | int (* seq_show)(struct seq_file *, void *)) | ||
665 | { | ||
666 | return 0; | ||
667 | } | ||
668 | |||
669 | void bt_procfs_cleanup(struct net *net, const char *name) | ||
670 | { | ||
671 | } | ||
672 | #endif | ||
673 | EXPORT_SYMBOL(bt_procfs_init); | ||
674 | EXPORT_SYMBOL(bt_procfs_cleanup); | ||
675 | |||
535 | static struct net_proto_family bt_sock_family_ops = { | 676 | static struct net_proto_family bt_sock_family_ops = { |
536 | .owner = THIS_MODULE, | 677 | .owner = THIS_MODULE, |
537 | .family = PF_BLUETOOTH, | 678 | .family = PF_BLUETOOTH, |