Commit 4b283d59 authored by Maksim Krasnyanskiy's avatar Maksim Krasnyanskiy Committed by Marcel Holtmann

Improved support for /proc/bluetooth

- Convert /proc/bluetoth/l2cap to seq_file
- Convert /proc/bluetoth/rfcomm to seq_file
- Convert /proc/bluetooth/sco to seq_file
- Export HCI device info via /proc/bluetooth/hci/N
	 
parent da15d7b1
...@@ -63,6 +63,8 @@ ...@@ -63,6 +63,8 @@
#define BT_DMP(D...) #define BT_DMP(D...)
#endif #endif
extern struct proc_dir_entry *proc_bt;
/* Connection and socket states */ /* Connection and socket states */
enum { enum {
BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */ BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#ifndef __HCI_CORE_H #ifndef __HCI_CORE_H
#define __HCI_CORE_H #define __HCI_CORE_H
#include <linux/proc_fs.h>
#include <net/bluetooth/hci.h> #include <net/bluetooth/hci.h>
/* HCI upper protocols */ /* HCI upper protocols */
...@@ -37,6 +38,8 @@ ...@@ -37,6 +38,8 @@
#define HCI_INIT_TIMEOUT (HZ * 10) #define HCI_INIT_TIMEOUT (HZ * 10)
extern struct proc_dir_entry *proc_bt_hci;
/* HCI Core structures */ /* HCI Core structures */
struct inquiry_entry { struct inquiry_entry {
...@@ -111,6 +114,10 @@ struct hci_dev { ...@@ -111,6 +114,10 @@ struct hci_dev {
atomic_t promisc; atomic_t promisc;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc;
#endif
int (*open)(struct hci_dev *hdev); int (*open)(struct hci_dev *hdev);
int (*close)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev);
int (*flush)(struct hci_dev *hdev); int (*flush)(struct hci_dev *hdev);
...@@ -148,8 +155,8 @@ struct hci_conn { ...@@ -148,8 +155,8 @@ struct hci_conn {
}; };
extern struct hci_proto *hci_proto[]; extern struct hci_proto *hci_proto[];
extern struct list_head hdev_list; extern struct list_head hci_dev_list;
extern rwlock_t hdev_list_lock; extern rwlock_t hci_dev_list_lock;
/* ----- Inquiry cache ----- */ /* ----- Inquiry cache ----- */
#define INQUIRY_CACHE_AGE_MAX (HZ*30) // 30 seconds #define INQUIRY_CACHE_AGE_MAX (HZ*30) // 30 seconds
...@@ -345,6 +352,9 @@ static inline int hci_recv_frame(struct sk_buff *skb) ...@@ -345,6 +352,9 @@ static inline int hci_recv_frame(struct sk_buff *skb)
return 0; return 0;
} }
int hci_dev_proc_init(struct hci_dev *hdev);
void hci_dev_proc_cleanup(struct hci_dev *hdev);
/* ----- LMP capabilities ----- */ /* ----- LMP capabilities ----- */
#define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH) #define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH)
#define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT) #define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT)
......
...@@ -345,4 +345,6 @@ int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg); ...@@ -345,4 +345,6 @@ int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg);
int rfcomm_init_ttys(void); int rfcomm_init_ttys(void);
void rfcomm_cleanup_ttys(void); void rfcomm_cleanup_ttys(void);
extern struct proc_dir_entry *proc_bt_rfcomm;
#endif /* __RFCOMM_H */ #endif /* __RFCOMM_H */
...@@ -10,6 +10,6 @@ obj-$(CONFIG_BT_SCO) += sco.o ...@@ -10,6 +10,6 @@ obj-$(CONFIG_BT_SCO) += sco.o
obj-$(CONFIG_BT_RFCOMM) += rfcomm/ obj-$(CONFIG_BT_RFCOMM) += rfcomm/
obj-$(CONFIG_BT_BNEP) += bnep/ obj-$(CONFIG_BT_BNEP) += bnep/
bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_proc.o lib.o syms.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -56,6 +56,10 @@ ...@@ -56,6 +56,10 @@
#define BT_DBG( A... ) #define BT_DBG( A... )
#endif #endif
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_bt;
#endif
/* Bluetooth sockets */ /* Bluetooth sockets */
#define BT_MAX_PROTO 5 #define BT_MAX_PROTO 5
static struct net_proto_family *bt_proto[BT_MAX_PROTO]; static struct net_proto_family *bt_proto[BT_MAX_PROTO];
...@@ -323,12 +327,14 @@ struct net_proto_family bt_sock_family_ops = ...@@ -323,12 +327,14 @@ struct net_proto_family bt_sock_family_ops =
extern int hci_sock_init(void); extern int hci_sock_init(void);
extern int hci_sock_cleanup(void); extern int hci_sock_cleanup(void);
extern int hci_proc_init(void);
extern int hci_proc_cleanup(void);
static int __init bt_init(void) static int __init bt_init(void)
{ {
BT_INFO("Core ver %s", VERSION); BT_INFO("Core ver %s", VERSION);
proc_mkdir("bluetooth", NULL); proc_bt = proc_mkdir("bluetooth", NULL);
/* Init socket cache */ /* Init socket cache */
bt_sock_cache = kmem_cache_create("bt_sock", bt_sock_cache = kmem_cache_create("bt_sock",
...@@ -344,6 +350,7 @@ static int __init bt_init(void) ...@@ -344,6 +350,7 @@ static int __init bt_init(void)
BT_INFO("HCI device and connection manager initialized"); BT_INFO("HCI device and connection manager initialized");
hci_proc_init();
hci_sock_init(); hci_sock_init();
return 0; return 0;
} }
...@@ -351,6 +358,7 @@ static int __init bt_init(void) ...@@ -351,6 +358,7 @@ static int __init bt_init(void)
static void __exit bt_cleanup(void) static void __exit bt_cleanup(void)
{ {
hci_sock_cleanup(); hci_sock_cleanup();
hci_proc_cleanup();
sock_unregister(PF_BLUETOOTH); sock_unregister(PF_BLUETOOTH);
kmem_cache_destroy(bt_sock_cache); kmem_cache_destroy(bt_sock_cache);
......
...@@ -215,9 +215,9 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) ...@@ -215,9 +215,9 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
BT_DBG("%s -> %s", batostr(src), batostr(dst)); BT_DBG("%s -> %s", batostr(src), batostr(dst));
read_lock_bh(&hdev_list_lock); read_lock_bh(&hci_dev_list_lock);
list_for_each(p, &hdev_list) { list_for_each(p, &hci_dev_list) {
struct hci_dev *d; struct hci_dev *d;
d = list_entry(p, struct hci_dev, list); d = list_entry(p, struct hci_dev, list);
...@@ -243,7 +243,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) ...@@ -243,7 +243,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
if (hdev) if (hdev)
hci_dev_hold(hdev); hci_dev_hold(hdev);
read_unlock_bh(&hdev_list_lock); read_unlock_bh(&hci_dev_list_lock);
return hdev; return hdev;
} }
......
...@@ -66,8 +66,8 @@ static void hci_notify(struct hci_dev *hdev, int event); ...@@ -66,8 +66,8 @@ static void hci_notify(struct hci_dev *hdev, int event);
rwlock_t hci_task_lock = RW_LOCK_UNLOCKED; rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
/* HCI device list */ /* HCI device list */
LIST_HEAD(hdev_list); LIST_HEAD(hci_dev_list);
rwlock_t hdev_list_lock = RW_LOCK_UNLOCKED; rwlock_t hci_dev_list_lock = RW_LOCK_UNLOCKED;
/* HCI protocols */ /* HCI protocols */
#define HCI_MAX_PROTO 2 #define HCI_MAX_PROTO 2
...@@ -298,8 +298,8 @@ struct hci_dev *hci_dev_get(int index) ...@@ -298,8 +298,8 @@ struct hci_dev *hci_dev_get(int index)
if (index < 0) if (index < 0)
return NULL; return NULL;
read_lock(&hdev_list_lock); read_lock(&hci_dev_list_lock);
list_for_each(p, &hdev_list) { list_for_each(p, &hci_dev_list) {
hdev = list_entry(p, struct hci_dev, list); hdev = list_entry(p, struct hci_dev, list);
if (hdev->id == index) { if (hdev->id == index) {
hci_dev_hold(hdev); hci_dev_hold(hdev);
...@@ -308,7 +308,7 @@ struct hci_dev *hci_dev_get(int index) ...@@ -308,7 +308,7 @@ struct hci_dev *hci_dev_get(int index)
} }
hdev = NULL; hdev = NULL;
done: done:
read_unlock(&hdev_list_lock); read_unlock(&hci_dev_list_lock);
return hdev; return hdev;
} }
...@@ -727,8 +727,8 @@ int hci_get_dev_list(unsigned long arg) ...@@ -727,8 +727,8 @@ int hci_get_dev_list(unsigned long arg)
return -ENOMEM; return -ENOMEM;
dr = dl->dev_req; dr = dl->dev_req;
read_lock_bh(&hdev_list_lock); read_lock_bh(&hci_dev_list_lock);
list_for_each(p, &hdev_list) { list_for_each(p, &hci_dev_list) {
struct hci_dev *hdev; struct hci_dev *hdev;
hdev = list_entry(p, struct hci_dev, list); hdev = list_entry(p, struct hci_dev, list);
(dr + n)->dev_id = hdev->id; (dr + n)->dev_id = hdev->id;
...@@ -736,7 +736,7 @@ int hci_get_dev_list(unsigned long arg) ...@@ -736,7 +736,7 @@ int hci_get_dev_list(unsigned long arg)
if (++n >= dev_num) if (++n >= dev_num)
break; break;
} }
read_unlock_bh(&hdev_list_lock); read_unlock_bh(&hci_dev_list_lock);
dl->dev_num = n; dl->dev_num = n;
size = n * sizeof(struct hci_dev_req) + sizeof(__u16); size = n * sizeof(struct hci_dev_req) + sizeof(__u16);
...@@ -787,7 +787,7 @@ int hci_get_dev_info(unsigned long arg) ...@@ -787,7 +787,7 @@ int hci_get_dev_info(unsigned long arg)
/* Register HCI device */ /* Register HCI device */
int hci_register_dev(struct hci_dev *hdev) int hci_register_dev(struct hci_dev *hdev)
{ {
struct list_head *head = &hdev_list, *p; struct list_head *head = &hci_dev_list, *p;
int id = 0; int id = 0;
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
...@@ -795,10 +795,10 @@ int hci_register_dev(struct hci_dev *hdev) ...@@ -795,10 +795,10 @@ int hci_register_dev(struct hci_dev *hdev)
if (!hdev->open || !hdev->close || !hdev->destruct) if (!hdev->open || !hdev->close || !hdev->destruct)
return -EINVAL; return -EINVAL;
write_lock_bh(&hdev_list_lock); write_lock_bh(&hci_dev_list_lock);
/* Find first available device id */ /* Find first available device id */
list_for_each(p, &hdev_list) { list_for_each(p, &hci_dev_list) {
if (list_entry(p, struct hci_dev, list)->id != id) if (list_entry(p, struct hci_dev, list)->id != id)
break; break;
head = p; id++; head = p; id++;
...@@ -836,7 +836,9 @@ int hci_register_dev(struct hci_dev *hdev) ...@@ -836,7 +836,9 @@ int hci_register_dev(struct hci_dev *hdev)
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
write_unlock_bh(&hdev_list_lock); write_unlock_bh(&hci_dev_list_lock);
hci_dev_proc_init(hdev);
hci_notify(hdev, HCI_DEV_REG); hci_notify(hdev, HCI_DEV_REG);
hci_run_hotplug(hdev->name, "register"); hci_run_hotplug(hdev->name, "register");
...@@ -849,9 +851,11 @@ int hci_unregister_dev(struct hci_dev *hdev) ...@@ -849,9 +851,11 @@ int hci_unregister_dev(struct hci_dev *hdev)
{ {
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
write_lock_bh(&hdev_list_lock); hci_dev_proc_cleanup(hdev);
write_lock_bh(&hci_dev_list_lock);
list_del(&hdev->list); list_del(&hdev->list);
write_unlock_bh(&hdev_list_lock); write_unlock_bh(&hci_dev_list_lock);
hci_dev_do_close(hdev); hci_dev_do_close(hdev);
......
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
/*
* Bluetooth HCI Proc FS support.
*
* $Id: hci_proc.c,v 1.0 2002/04/17 17:37:16 maxk Exp $
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <net/sock.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#ifndef CONFIG_BT_HCI_CORE_DEBUG
#undef BT_DBG
#define BT_DBG( A... )
#endif
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_bt_hci;
static int hci_seq_open(struct file *file, struct seq_operations *op, void *priv)
{
struct seq_file *seq;
if (seq_open(file, op))
return -ENOMEM;
seq = file->private_data;
seq->private = priv;
return 0;
}
static void *inq_seq_start(struct seq_file *seq, loff_t *pos)
{
struct hci_dev *hdev = seq->private;
struct inquiry_entry *inq;
loff_t l = *pos;
hci_dev_lock_bh(hdev);
for (inq = hdev->inq_cache.list; inq; inq = inq->next)
if (!l--)
return inq;
return NULL;
}
static void *inq_seq_next(struct seq_file *seq, void *e, loff_t *pos)
{
struct inquiry_entry *inq = e;
return inq->next;
}
static void inq_seq_stop(struct seq_file *seq, void *e)
{
struct hci_dev *hdev = seq->private;
hci_dev_unlock_bh(hdev);
}
static int inq_seq_show(struct seq_file *seq, void *e)
{
struct inquiry_entry *inq = e;
struct inquiry_info *info = &inq->info;
seq_printf(seq, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %u\n", batostr(&info->bdaddr),
info->pscan_rep_mode, info->pscan_period_mode, info->pscan_mode,
info->dev_class[0], info->dev_class[1], info->dev_class[2],
info->clock_offset, inq->timestamp);
return 0;
}
static struct seq_operations inq_seq_ops = {
.start = inq_seq_start,
.next = inq_seq_next,
.stop = inq_seq_stop,
.show = inq_seq_show
};
static int inq_seq_open(struct inode *inode, struct file *file)
{
return hci_seq_open(file, &inq_seq_ops, PDE(inode)->data);
}
static struct file_operations inq_seq_fops = {
.open = inq_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
int hci_dev_proc_init(struct hci_dev *hdev)
{
struct proc_dir_entry *e;
char id[10];
sprintf(id, "%d", hdev->id);
hdev->proc = proc_mkdir(id, proc_bt_hci);
if (!hdev->proc)
return -ENOMEM;
e = create_proc_entry("inquiry_cache", S_IRUGO, hdev->proc);
if (e) {
e->proc_fops = &inq_seq_fops;
e->data = (void *) hdev;
}
return 0;
}
void hci_dev_proc_cleanup(struct hci_dev *hdev)
{
char id[10];
sprintf(id, "%d", hdev->id);
remove_proc_entry("inquiry_cache", hdev->proc);
remove_proc_entry(id, proc_bt_hci);
}
int __init hci_proc_init(void)
{
proc_bt_hci = proc_mkdir("hci", proc_bt);
return 0;
}
void __init hci_proc_cleanup(void)
{
remove_proc_entry("hci", proc_bt);
}
#else /* CONFIG_PROC_FS */
int hci_dev_proc_init(struct hci_dev *hdev)
{
return 0;
}
void hci_dev_proc_cleanup(struct hci_dev *hdev)
{
return;
}
int __init hci_proc_init(void)
{
return 0;
}
void __init hci_proc_cleanup(void)
{
return;
}
#endif /* CONFIG_PROC_FS */
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/list.h> #include <linux/list.h>
#include <net/sock.h> #include <net/sock.h>
...@@ -1993,51 +1994,89 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl ...@@ -1993,51 +1994,89 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
} }
/* ---- Proc fs support ---- */ /* ---- Proc fs support ---- */
static int l2cap_sock_dump(char *buf, struct bt_sock_list *list) #ifdef CONFIG_PROC_FS
static void *l2cap_seq_start(struct seq_file *seq, loff_t *pos)
{ {
struct l2cap_pinfo *pi;
struct sock *sk; struct sock *sk;
char *ptr = buf; loff_t l = *pos;
read_lock_bh(&list->lock); read_lock_bh(&l2cap_sk_list.lock);
for (sk = list->head; sk; sk = sk->next) { for (sk = l2cap_sk_list.head; sk; sk = sk->next)
pi = l2cap_pi(sk); if (!l--)
ptr += sprintf(ptr, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n", return sk;
return NULL;
}
static void *l2cap_seq_next(struct seq_file *seq, void *e, loff_t *pos)
{
struct sock *sk = e;
(*pos)++;
return sk->next;
}
static void l2cap_seq_stop(struct seq_file *seq, void *e)
{
read_unlock_bh(&l2cap_sk_list.lock);
}
static int l2cap_seq_show(struct seq_file *seq, void *e)
{
struct sock *sk = e;
struct l2cap_pinfo *pi = l2cap_pi(sk);
seq_printf(seq, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu, sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu,
pi->link_mode); pi->link_mode);
} return 0;
read_unlock_bh(&list->lock);
ptr += sprintf(ptr, "\n");
return ptr - buf;
} }
static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) static struct seq_operations l2cap_seq_ops = {
.start = l2cap_seq_start,
.next = l2cap_seq_next,
.stop = l2cap_seq_stop,
.show = l2cap_seq_show
};
static int l2cap_seq_open(struct inode *inode, struct file *file)
{ {
char *ptr = buf; return seq_open(file, &l2cap_seq_ops);
int len; }
BT_DBG("count %d, offset %ld", count, offset); static struct file_operations l2cap_seq_fops = {
.open = l2cap_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
ptr += l2cap_sock_dump(ptr, &l2cap_sk_list); static int __init l2cap_proc_init(void)
len = ptr - buf; {
struct proc_dir_entry *p = create_proc_entry("l2cap", S_IRUGO, proc_bt);
if (!p)
return -ENOMEM;
p->proc_fops = &l2cap_seq_fops;
return 0;
}
if (len <= count + offset) static void __init l2cap_proc_cleanup(void)
*eof = 1; {
remove_proc_entry("l2cap", proc_bt);
}
*start = buf + offset; #else /* CONFIG_PROC_FS */
len -= offset;
if (len > count) static int __init l2cap_proc_init(void)
len = count; {
if (len < 0) return 0;
len = 0; }
return len; static void __init l2cap_proc_cleanup(void)
{
return 0;
} }
#endif /* CONFIG_PROC_FS */
static struct proto_ops l2cap_sock_ops = { static struct proto_ops l2cap_sock_ops = {
.family = PF_BLUETOOTH, .family = PF_BLUETOOTH,
...@@ -2088,7 +2127,8 @@ int __init l2cap_init(void) ...@@ -2088,7 +2127,8 @@ int __init l2cap_init(void)
return err; return err;
} }
create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
l2cap_proc_init();
BT_INFO("L2CAP ver %s", VERSION); BT_INFO("L2CAP ver %s", VERSION);
BT_INFO("L2CAP socket layer initialized"); BT_INFO("L2CAP socket layer initialized");
...@@ -2098,7 +2138,7 @@ int __init l2cap_init(void) ...@@ -2098,7 +2138,7 @@ int __init l2cap_init(void)
void l2cap_cleanup(void) void l2cap_cleanup(void)
{ {
remove_proc_entry("bluetooth/l2cap", NULL); l2cap_proc_cleanup();
/* Unregister socket and protocol */ /* Unregister socket and protocol */
if (bt_sock_unregister(BTPROTO_L2CAP)) if (bt_sock_unregister(BTPROTO_L2CAP))
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <net/sock.h> #include <net/sock.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
...@@ -58,6 +59,10 @@ ...@@ -58,6 +59,10 @@
#define BT_DBG(D...) #define BT_DBG(D...)
#endif #endif
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_bt_rfcomm;
#endif
struct task_struct *rfcomm_thread; struct task_struct *rfcomm_thread;
DECLARE_MUTEX(rfcomm_sem); DECLARE_MUTEX(rfcomm_sem);
unsigned long rfcomm_event; unsigned long rfcomm_event;
...@@ -1723,60 +1728,112 @@ static int rfcomm_run(void *unused) ...@@ -1723,60 +1728,112 @@ static int rfcomm_run(void *unused)
} }
/* ---- Proc fs support ---- */ /* ---- Proc fs support ---- */
static int rfcomm_dlc_dump(char *buf) #ifdef CONFIG_PROC_FS
static void *rfcomm_seq_start(struct seq_file *seq, loff_t *pos)
{ {
struct rfcomm_session *s; struct rfcomm_session *s;
struct sock *sk; struct list_head *pp, *p;
struct list_head *p, *pp; loff_t l = *pos;
char *ptr = buf;
rfcomm_lock(); rfcomm_lock();
list_for_each(p, &session_list) { list_for_each(p, &session_list) {
s = list_entry(p, struct rfcomm_session, list); s = list_entry(p, struct rfcomm_session, list);
sk = s->sock->sk; list_for_each(pp, &s->dlcs)
if (!l--) {
seq->private = s;
return pp;
}
}
return NULL;
}
list_for_each(pp, &s->dlcs) { static void *rfcomm_seq_next(struct seq_file *seq, void *e, loff_t *pos)
struct rfcomm_dlc *d; {
d = list_entry(pp, struct rfcomm_dlc, list); struct rfcomm_session *s = seq->private;
struct list_head *pp, *p = e;
(*pos)++;
ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n", if (p->next != &s->dlcs)
batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), return p->next;
d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
for (p = s->list.next; p != &session_list; p = p->next) {
s = list_entry(p, struct rfcomm_session, list);
__list_for_each(pp, &s->dlcs) {
seq->private = s;
return pp;
} }
} }
return NULL;
}
static void rfcomm_seq_stop(struct seq_file *seq, void *e)
{
rfcomm_unlock(); rfcomm_unlock();
}
static int rfcomm_seq_show(struct seq_file *seq, void *e)
{
struct rfcomm_session *s = seq->private;
struct sock *sk = s->sock->sk;
struct rfcomm_dlc *d = list_entry(e, struct rfcomm_dlc, list);
seq_printf(seq, "%s %s %ld %d %d %d %d\n",
batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
return 0;
}
return ptr - buf; static struct seq_operations rfcomm_seq_ops = {
.start = rfcomm_seq_start,
.next = rfcomm_seq_next,
.stop = rfcomm_seq_stop,
.show = rfcomm_seq_show
};
static int rfcomm_seq_open(struct inode *inode, struct file *file)
{
return seq_open(file, &rfcomm_seq_ops);
} }
extern int rfcomm_sock_dump(char *buf); static struct file_operations rfcomm_seq_fops = {
.open = rfcomm_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) static int __init rfcomm_proc_init(void)
{ {
char *ptr = buf; struct proc_dir_entry *p;
int len;
BT_DBG("count %d, offset %ld", count, offset); proc_bt_rfcomm = proc_mkdir("rfcomm", proc_bt);
ptr += rfcomm_dlc_dump(ptr); p = create_proc_entry("dlc", S_IRUGO, proc_bt_rfcomm);
ptr += rfcomm_sock_dump(ptr); if (p)
len = ptr - buf; p->proc_fops = &rfcomm_seq_fops;
return 0;
}
if (len <= count + offset) static void __init rfcomm_proc_cleanup(void)
*eof = 1; {
remove_proc_entry("dlc", proc_bt_rfcomm);
*start = buf + offset; remove_proc_entry("rfcomm", proc_bt);
len -= offset; }
if (len > count) #else /* CONFIG_PROC_FS */
len = count;
if (len < 0)
len = 0;
return len; static int __init rfcomm_proc_init(void)
{
return 0;
}
static void __init rfcomm_proc_cleanup(void)
{
return 0;
} }
#endif /* CONFIG_PROC_FS */
/* ---- Initialization ---- */ /* ---- Initialization ---- */
int __init rfcomm_init(void) int __init rfcomm_init(void)
...@@ -1785,14 +1842,14 @@ int __init rfcomm_init(void) ...@@ -1785,14 +1842,14 @@ int __init rfcomm_init(void)
BT_INFO("RFCOMM ver %s", VERSION); BT_INFO("RFCOMM ver %s", VERSION);
rfcomm_proc_init();
rfcomm_init_sockets(); rfcomm_init_sockets();
#ifdef CONFIG_BT_RFCOMM_TTY #ifdef CONFIG_BT_RFCOMM_TTY
rfcomm_init_ttys(); rfcomm_init_ttys();
#endif #endif
create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL);
return 0; return 0;
} }
...@@ -1807,14 +1864,13 @@ void rfcomm_cleanup(void) ...@@ -1807,14 +1864,13 @@ void rfcomm_cleanup(void)
while (atomic_read(&running)) while (atomic_read(&running))
schedule(); schedule();
remove_proc_entry("bluetooth/rfcomm", NULL);
#ifdef CONFIG_BT_RFCOMM_TTY #ifdef CONFIG_BT_RFCOMM_TTY
rfcomm_cleanup_ttys(); rfcomm_cleanup_ttys();
#endif #endif
rfcomm_cleanup_sockets(); rfcomm_cleanup_sockets();
return;
rfcomm_proc_cleanup();
} }
module_init(rfcomm_init); module_init(rfcomm_init);
......
...@@ -44,6 +44,8 @@ ...@@ -44,6 +44,8 @@
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <net/sock.h> #include <net/sock.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -772,27 +774,87 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * ...@@ -772,27 +774,87 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
} }
/* ---- Proc fs support ---- */ /* ---- Proc fs support ---- */
int rfcomm_sock_dump(char *buf) #ifdef CONFIG_PROC_FS
static void *rfcomm_seq_start(struct seq_file *seq, loff_t *pos)
{ {
struct bt_sock_list *list = &rfcomm_sk_list;
struct rfcomm_pinfo *pi;
struct sock *sk; struct sock *sk;
char *ptr = buf; loff_t l = *pos;
write_lock_bh(&list->lock); read_lock_bh(&rfcomm_sk_list.lock);
for (sk = list->head; sk; sk = sk->next) { for (sk = rfcomm_sk_list.head; sk; sk = sk->next)
pi = rfcomm_pi(sk); if (!l--)
ptr += sprintf(ptr, "sk %s %s %d %d\n", return sk;
return NULL;
}
static void *rfcomm_seq_next(struct seq_file *seq, void *e, loff_t *pos)
{
struct sock *sk = e;
(*pos)++;
return sk->next;
}
static void rfcomm_seq_stop(struct seq_file *seq, void *e)
{
read_unlock_bh(&rfcomm_sk_list.lock);
}
static int rfcomm_seq_show(struct seq_file *seq, void *e)
{
struct sock *sk = e;
seq_printf(seq, "%s %s %d %d\n",
batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
sk->state, rfcomm_pi(sk)->channel); sk->state, rfcomm_pi(sk)->channel);
} return 0;
}
write_unlock_bh(&list->lock); static struct seq_operations rfcomm_seq_ops = {
.start = rfcomm_seq_start,
.next = rfcomm_seq_next,
.stop = rfcomm_seq_stop,
.show = rfcomm_seq_show
};
return ptr - buf; static int rfcomm_seq_open(struct inode *inode, struct file *file)
{
return seq_open(file, &rfcomm_seq_ops);
} }
static struct file_operations rfcomm_seq_fops = {
.open = rfcomm_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int __init rfcomm_sock_proc_init(void)
{
struct proc_dir_entry *p = create_proc_entry("sock", S_IRUGO, proc_bt_rfcomm);
if (!p)
return -ENOMEM;
p->proc_fops = &rfcomm_seq_fops;
return 0;
}
static void __init rfcomm_sock_proc_cleanup(void)
{
remove_proc_entry("sock", proc_bt_rfcomm);
}
#else /* CONFIG_PROC_FS */
static int __init rfcomm_sock_proc_init(void)
{
return 0;
}
static void __init rfcomm_sock_proc_cleanup(void)
{
return 0;
}
#endif /* CONFIG_PROC_FS */
static struct proto_ops rfcomm_sock_ops = { static struct proto_ops rfcomm_sock_ops = {
.family = PF_BLUETOOTH, .family = PF_BLUETOOTH,
.release = rfcomm_sock_release, .release = rfcomm_sock_release,
...@@ -826,6 +888,8 @@ int rfcomm_init_sockets(void) ...@@ -826,6 +888,8 @@ int rfcomm_init_sockets(void)
return err; return err;
} }
rfcomm_sock_proc_init();
BT_INFO("RFCOMM socket layer initialized"); BT_INFO("RFCOMM socket layer initialized");
return 0; return 0;
} }
...@@ -834,6 +898,8 @@ void rfcomm_cleanup_sockets(void) ...@@ -834,6 +898,8 @@ void rfcomm_cleanup_sockets(void)
{ {
int err; int err;
rfcomm_sock_proc_cleanup();
/* Unregister socket, protocol and notifier */ /* Unregister socket, protocol and notifier */
if ((err = bt_sock_unregister(BTPROTO_RFCOMM))) if ((err = bt_sock_unregister(BTPROTO_RFCOMM)))
BT_ERR("RFCOMM socket layer unregistration failed. %d", err); BT_ERR("RFCOMM socket layer unregistration failed. %d", err);
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/list.h> #include <linux/list.h>
#include <net/sock.h> #include <net/sock.h>
...@@ -884,52 +885,86 @@ int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) ...@@ -884,52 +885,86 @@ int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
return 0; return 0;
} }
/* ----- Proc fs support ------ */ /* ---- Proc fs support ---- */
static int sco_sock_dump(char *buf, struct bt_sock_list *list) #ifdef CONFIG_PROC_FS
static void *sco_seq_start(struct seq_file *seq, loff_t *pos)
{ {
struct sco_pinfo *pi;
struct sock *sk; struct sock *sk;
char *ptr = buf; loff_t l = *pos;
read_lock_bh(&list->lock); read_lock_bh(&sco_sk_list.lock);
for (sk = list->head; sk; sk = sk->next) { for (sk = sco_sk_list.head; sk; sk = sk->next)
pi = sco_pi(sk); if (!l--)
ptr += sprintf(ptr, "%s %s %d\n", return sk;
batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), return NULL;
sk->state); }
}
read_unlock_bh(&list->lock); static void *sco_seq_next(struct seq_file *seq, void *e, loff_t *pos)
{
struct sock *sk = e;
(*pos)++;
return sk->next;
}
ptr += sprintf(ptr, "\n"); static void sco_seq_stop(struct seq_file *seq, void *e)
{
read_unlock_bh(&sco_sk_list.lock);
}
return ptr - buf; static int sco_seq_show(struct seq_file *seq, void *e)
{
struct sock *sk = e;
seq_printf(seq, "%s %s %d\n",
batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->state);
return 0;
} }
static int sco_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) static struct seq_operations sco_seq_ops = {
.start = sco_seq_start,
.next = sco_seq_next,
.stop = sco_seq_stop,
.show = sco_seq_show
};
static int sco_seq_open(struct inode *inode, struct file *file)
{ {
char *ptr = buf; return seq_open(file, &sco_seq_ops);
int len; }
BT_DBG("count %d, offset %ld", count, offset); static struct file_operations sco_seq_fops = {
.open = sco_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
ptr += sco_sock_dump(ptr, &sco_sk_list); static int __init sco_proc_init(void)
len = ptr - buf; {
struct proc_dir_entry *p = create_proc_entry("sco", S_IRUGO, proc_bt);
if (!p)
return -ENOMEM;
p->proc_fops = &sco_seq_fops;
return 0;
}
if (len <= count + offset) static void __init sco_proc_cleanup(void)
*eof = 1; {
remove_proc_entry("sco", proc_bt);
}
*start = buf + offset; #else /* CONFIG_PROC_FS */
len -= offset;
if (len > count) static int __init sco_proc_init(void)
len = count; {
if (len < 0) return 0;
len = 0; }
return len; static void __init sco_proc_cleanup(void)
{
return 0;
} }
#endif /* CONFIG_PROC_FS */
static struct proto_ops sco_sock_ops = { static struct proto_ops sco_sock_ops = {
.family = PF_BLUETOOTH, .family = PF_BLUETOOTH,
...@@ -978,7 +1013,7 @@ int __init sco_init(void) ...@@ -978,7 +1013,7 @@ int __init sco_init(void)
return err; return err;
} }
create_proc_read_entry("bluetooth/sco", 0, 0, sco_read_proc, NULL); sco_proc_init();
BT_INFO("SCO (Voice Link) ver %s", VERSION); BT_INFO("SCO (Voice Link) ver %s", VERSION);
BT_INFO("SCO socket layer initialized"); BT_INFO("SCO socket layer initialized");
...@@ -990,7 +1025,7 @@ void sco_cleanup(void) ...@@ -990,7 +1025,7 @@ void sco_cleanup(void)
{ {
int err; int err;
remove_proc_entry("bluetooth/sco", NULL); sco_proc_cleanup();
/* Unregister socket, protocol and notifier */ /* Unregister socket, protocol and notifier */
if ((err = bt_sock_unregister(BTPROTO_SCO))) if ((err = bt_sock_unregister(BTPROTO_SCO)))
......
...@@ -78,3 +78,5 @@ EXPORT_SYMBOL(bt_sock_poll); ...@@ -78,3 +78,5 @@ EXPORT_SYMBOL(bt_sock_poll);
EXPORT_SYMBOL(bt_accept_enqueue); EXPORT_SYMBOL(bt_accept_enqueue);
EXPORT_SYMBOL(bt_accept_dequeue); EXPORT_SYMBOL(bt_accept_dequeue);
EXPORT_SYMBOL(bt_sock_w4_connect); EXPORT_SYMBOL(bt_sock_w4_connect);
EXPORT_SYMBOL(proc_bt);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment