aboutsummaryrefslogtreecommitdiff
path: root/net/bluetooth/af_bluetooth.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/af_bluetooth.c')
-rw-r--r--net/bluetooth/af_bluetooth.c117
1 files changed, 76 insertions, 41 deletions
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 5355df63d39..2021c481cdb 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -25,12 +25,13 @@
/* Bluetooth address family and sockets. */
#include <linux/module.h>
+#include <linux/debugfs.h>
#include <asm/ioctls.h>
#include <net/bluetooth/bluetooth.h>
#include <linux/proc_fs.h>
-#define VERSION "2.16"
+#define VERSION "2.19"
/* Bluetooth sockets */
#define BT_MAX_PROTO 8
@@ -92,23 +93,14 @@ int bt_sock_register(int proto, const struct net_proto_family *ops)
}
EXPORT_SYMBOL(bt_sock_register);
-int bt_sock_unregister(int proto)
+void bt_sock_unregister(int proto)
{
- int err = 0;
-
if (proto < 0 || proto >= BT_MAX_PROTO)
- return -EINVAL;
+ return;
write_lock(&bt_proto_lock);
-
- if (!bt_proto[proto])
- err = -ENOENT;
- else
- bt_proto[proto] = NULL;
-
+ bt_proto[proto] = NULL;
write_unlock(&bt_proto_lock);
-
- return err;
}
EXPORT_SYMBOL(bt_sock_unregister);
@@ -234,11 +226,10 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
if (!skb) {
if (sk->sk_shutdown & RCV_SHUTDOWN)
return 0;
+
return err;
}
- msg->msg_namelen = 0;
-
copied = skb->len;
if (len < copied) {
msg->msg_flags |= MSG_TRUNC;
@@ -247,9 +238,14 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
skb_reset_transport_header(skb);
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
- if (err == 0)
+ if (err == 0) {
sock_recv_ts_and_drops(msg, sk, skb);
+ if (bt_sk(sk)->skb_msg_name)
+ bt_sk(sk)->skb_msg_name(skb, msg->msg_name,
+ &msg->msg_namelen);
+ }
+
skb_free_datagram(sk, skb);
return err ? : copied;
@@ -296,8 +292,6 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
if (flags & MSG_OOB)
return -EOPNOTSUPP;
- msg->msg_namelen = 0;
-
BT_DBG("sk %p size %zu", sk, size);
lock_sock(sk);
@@ -422,7 +416,8 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock,
return bt_accept_poll(sk);
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
- mask |= POLLERR;
+ mask |= POLLERR |
+ (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP | POLLIN | POLLRDNORM;
@@ -498,6 +493,7 @@ int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
}
EXPORT_SYMBOL(bt_sock_ioctl);
+/* This function expects the sk lock to be held when called */
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
{
DECLARE_WAITQUEUE(wait, current);
@@ -533,6 +529,46 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
}
EXPORT_SYMBOL(bt_sock_wait_state);
+/* This function expects the sk lock to be held when called */
+int bt_sock_wait_ready(struct sock *sk, unsigned long flags)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long timeo;
+ int err = 0;
+
+ BT_DBG("sk %p", sk);
+
+ timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
+
+ add_wait_queue(sk_sleep(sk), &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (test_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags)) {
+ if (!timeo) {
+ err = -EAGAIN;
+ break;
+ }
+
+ if (signal_pending(current)) {
+ err = sock_intr_errno(timeo);
+ break;
+ }
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ err = sock_error(sk);
+ if (err)
+ break;
+ }
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(sk_sleep(sk), &wait);
+
+ return err;
+}
+EXPORT_SYMBOL(bt_sock_wait_ready);
+
#ifdef CONFIG_PROC_FS
struct bt_seq_state {
struct bt_sock_list *l;
@@ -571,7 +607,7 @@ static int bt_seq_show(struct seq_file *seq, void *v)
struct bt_sock_list *l = s->l;
if (v == SEQ_START_TOKEN) {
- seq_puts(seq ,"sk RefCnt Rmem Wmem User Inode Src Dst Parent");
+ seq_puts(seq ,"sk RefCnt Rmem Wmem User Inode Parent");
if (l->custom_seq_show) {
seq_putc(seq, ' ');
@@ -584,15 +620,13 @@ static int bt_seq_show(struct seq_file *seq, void *v)
struct bt_sock *bt = bt_sk(sk);
seq_printf(seq,
- "%pK %-6d %-6u %-6u %-6u %-6lu %pMR %pMR %-6lu",
+ "%pK %-6d %-6u %-6u %-6u %-6lu %-6lu",
sk,
atomic_read(&sk->sk_refcnt),
sk_rmem_alloc_get(sk),
sk_wmem_alloc_get(sk),
from_kuid(seq_user_ns(seq), sock_i_uid(sk)),
sock_i_ino(sk),
- &bt->src,
- &bt->dst,
bt->parent? sock_i_ino(bt->parent): 0LU);
if (l->custom_seq_show) {
@@ -617,7 +651,7 @@ static int bt_seq_open(struct inode *inode, struct file *file)
struct bt_sock_list *sk_list;
struct bt_seq_state *s;
- sk_list = PDE(inode)->data;
+ sk_list = PDE_DATA(inode);
s = __seq_open_private(file, &bt_seq_ops,
sizeof(struct bt_seq_state));
if (!s)
@@ -627,35 +661,30 @@ static int bt_seq_open(struct inode *inode, struct file *file)
return 0;
}
-int bt_procfs_init(struct module* module, struct net *net, const char *name,
+static const struct file_operations bt_fops = {
+ .open = bt_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private
+};
+
+int bt_procfs_init(struct net *net, const char *name,
struct bt_sock_list* sk_list,
int (* seq_show)(struct seq_file *, void *))
{
- struct proc_dir_entry * pde;
-
sk_list->custom_seq_show = seq_show;
- sk_list->fops.owner = module;
- sk_list->fops.open = bt_seq_open;
- sk_list->fops.read = seq_read;
- sk_list->fops.llseek = seq_lseek;
- sk_list->fops.release = seq_release_private;
-
- pde = proc_net_fops_create(net, name, 0, &sk_list->fops);
- if (!pde)
+ if (!proc_create_data(name, 0, net->proc_net, &bt_fops, sk_list))
return -ENOMEM;
-
- pde->data = sk_list;
-
return 0;
}
void bt_procfs_cleanup(struct net *net, const char *name)
{
- proc_net_remove(net, name);
+ remove_proc_entry(name, net->proc_net);
}
#else
-int bt_procfs_init(struct module* module, struct net *net, const char *name,
+int bt_procfs_init(struct net *net, const char *name,
struct bt_sock_list* sk_list,
int (* seq_show)(struct seq_file *, void *))
{
@@ -675,12 +704,17 @@ static struct net_proto_family bt_sock_family_ops = {
.create = bt_sock_create,
};
+struct dentry *bt_debugfs;
+EXPORT_SYMBOL_GPL(bt_debugfs);
+
static int __init bt_init(void)
{
int err;
BT_INFO("Core ver %s", VERSION);
+ bt_debugfs = debugfs_create_dir("bluetooth", NULL);
+
err = bt_sysfs_init();
if (err < 0)
return err;
@@ -721,7 +755,6 @@ error:
static void __exit bt_exit(void)
{
-
sco_exit();
l2cap_exit();
@@ -731,6 +764,8 @@ static void __exit bt_exit(void)
sock_unregister(PF_BLUETOOTH);
bt_sysfs_cleanup();
+
+ debugfs_remove_recursive(bt_debugfs);
}
subsys_initcall(bt_init);