Bluetooth: Move dev_set_name() to a context that can sleep
[safe/jmp/linux-2.6] / net / bluetooth / af_bluetooth.c
index 1650c6b..02b9baa 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2000-2001 Qualcomm Incorporated
 
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2000-2001 Qualcomm Incorporated
 
    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
    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 
+   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.
 
    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 
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
    SOFTWARE IS DISCLAIMED.
 */
 
 /* Bluetooth address family and sockets. */
 
    SOFTWARE IS DISCLAIMED.
 */
 
 /* Bluetooth address family and sockets. */
 
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <linux/proc_fs.h>
 #include <net/sock.h>
 #include <net/sock.h>
-
-#if defined(CONFIG_KMOD)
+#include <asm/ioctls.h>
 #include <linux/kmod.h>
 #include <linux/kmod.h>
-#endif
 
 #include <net/bluetooth/bluetooth.h>
 
 
 #include <net/bluetooth/bluetooth.h>
 
-#ifndef CONFIG_BT_SOCK_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
-#define VERSION "2.7"
-
-struct proc_dir_entry *proc_bt;
-EXPORT_SYMBOL(proc_bt);
+#define VERSION "2.15"
 
 /* Bluetooth sockets */
 #define BT_MAX_PROTO   8
 static struct net_proto_family *bt_proto[BT_MAX_PROTO];
 
 /* Bluetooth sockets */
 #define BT_MAX_PROTO   8
 static struct net_proto_family *bt_proto[BT_MAX_PROTO];
+static DEFINE_RWLOCK(bt_proto_lock);
+
+static struct lock_class_key bt_lock_key[BT_MAX_PROTO];
+static const char *bt_key_strings[BT_MAX_PROTO] = {
+       "sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP",
+       "sk_lock-AF_BLUETOOTH-BTPROTO_HCI",
+       "sk_lock-AF_BLUETOOTH-BTPROTO_SCO",
+       "sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM",
+       "sk_lock-AF_BLUETOOTH-BTPROTO_BNEP",
+       "sk_lock-AF_BLUETOOTH-BTPROTO_CMTP",
+       "sk_lock-AF_BLUETOOTH-BTPROTO_HIDP",
+       "sk_lock-AF_BLUETOOTH-BTPROTO_AVDTP",
+};
+
+static struct lock_class_key bt_slock_key[BT_MAX_PROTO];
+static const char *bt_slock_key_strings[BT_MAX_PROTO] = {
+       "slock-AF_BLUETOOTH-BTPROTO_L2CAP",
+       "slock-AF_BLUETOOTH-BTPROTO_HCI",
+       "slock-AF_BLUETOOTH-BTPROTO_SCO",
+       "slock-AF_BLUETOOTH-BTPROTO_RFCOMM",
+       "slock-AF_BLUETOOTH-BTPROTO_BNEP",
+       "slock-AF_BLUETOOTH-BTPROTO_CMTP",
+       "slock-AF_BLUETOOTH-BTPROTO_HIDP",
+       "slock-AF_BLUETOOTH-BTPROTO_AVDTP",
+};
+
+static inline void bt_sock_reclassify_lock(struct socket *sock, int proto)
+{
+       struct sock *sk = sock->sk;
+
+       if (!sk)
+               return;
+
+       BUG_ON(sock_owned_by_user(sk));
+
+       sock_lock_init_class_and_name(sk,
+                       bt_slock_key_strings[proto], &bt_slock_key[proto],
+                               bt_key_strings[proto], &bt_lock_key[proto]);
+}
 
 int bt_sock_register(int proto, struct net_proto_family *ops)
 {
 
 int bt_sock_register(int proto, struct net_proto_family *ops)
 {
+       int err = 0;
+
        if (proto < 0 || proto >= BT_MAX_PROTO)
                return -EINVAL;
 
        if (proto < 0 || proto >= BT_MAX_PROTO)
                return -EINVAL;
 
+       write_lock(&bt_proto_lock);
+
        if (bt_proto[proto])
        if (bt_proto[proto])
-               return -EEXIST;
+               err = -EEXIST;
+       else
+               bt_proto[proto] = ops;
 
 
-       bt_proto[proto] = ops;
-       return 0;
+       write_unlock(&bt_proto_lock);
+
+       return err;
 }
 EXPORT_SYMBOL(bt_sock_register);
 
 int bt_sock_unregister(int proto)
 {
 }
 EXPORT_SYMBOL(bt_sock_register);
 
 int bt_sock_unregister(int proto)
 {
+       int err = 0;
+
        if (proto < 0 || proto >= BT_MAX_PROTO)
                return -EINVAL;
 
        if (proto < 0 || proto >= BT_MAX_PROTO)
                return -EINVAL;
 
+       write_lock(&bt_proto_lock);
+
        if (!bt_proto[proto])
        if (!bt_proto[proto])
-               return -ENOENT;
+               err = -ENOENT;
+       else
+               bt_proto[proto] = NULL;
 
 
-       bt_proto[proto] = NULL;
-       return 0;
+       write_unlock(&bt_proto_lock);
+
+       return err;
 }
 EXPORT_SYMBOL(bt_sock_unregister);
 
 }
 EXPORT_SYMBOL(bt_sock_unregister);
 
-static int bt_sock_create(struct socket *sock, int proto)
+static int bt_sock_create(struct net *net, struct socket *sock, int proto)
 {
 {
-       int err = 0;
+       int err;
+
+       if (net != &init_net)
+               return -EAFNOSUPPORT;
 
        if (proto < 0 || proto >= BT_MAX_PROTO)
                return -EINVAL;
 
 
        if (proto < 0 || proto >= BT_MAX_PROTO)
                return -EINVAL;
 
-#if defined(CONFIG_KMOD)
-       if (!bt_proto[proto]) {
+       if (!bt_proto[proto])
                request_module("bt-proto-%d", proto);
                request_module("bt-proto-%d", proto);
-       }
-#endif
+
        err = -EPROTONOSUPPORT;
        err = -EPROTONOSUPPORT;
+
+       read_lock(&bt_proto_lock);
+
        if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) {
        if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) {
-               err = bt_proto[proto]->create(sock, proto);
+               err = bt_proto[proto]->create(net, sock, proto);
+               bt_sock_reclassify_lock(sock, proto);
                module_put(bt_proto[proto]->owner);
        }
                module_put(bt_proto[proto]->owner);
        }
-       return err; 
+
+       read_unlock(&bt_proto_lock);
+
+       return err;
 }
 
 void bt_sock_link(struct bt_sock_list *l, struct sock *sk)
 }
 
 void bt_sock_link(struct bt_sock_list *l, struct sock *sk)
@@ -163,7 +211,8 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
                        continue;
                }
 
                        continue;
                }
 
-               if (sk->sk_state == BT_CONNECTED || !newsock) {
+               if (sk->sk_state == BT_CONNECTED || !newsock ||
+                                               bt_sk(parent)->defer_setup) {
                        bt_accept_unlink(sk);
                        if (newsock)
                                sock_graft(sk, newsock);
                        bt_accept_unlink(sk);
                        if (newsock)
                                sock_graft(sk, newsock);
@@ -178,7 +227,7 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
 EXPORT_SYMBOL(bt_accept_dequeue);
 
 int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
 EXPORT_SYMBOL(bt_accept_dequeue);
 
 int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
-       struct msghdr *msg, size_t len, int flags)
+                               struct msghdr *msg, size_t len, int flags)
 {
        int noblock = flags & MSG_DONTWAIT;
        struct sock *sk = sock->sk;
 {
        int noblock = flags & MSG_DONTWAIT;
        struct sock *sk = sock->sk;
@@ -186,7 +235,7 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
        size_t copied;
        int err;
 
        size_t copied;
        int err;
 
-       BT_DBG("sock %p sk %p len %d", sock, sk, len);
+       BT_DBG("sock %p sk %p len %zu", sock, sk, len);
 
        if (flags & (MSG_OOB))
                return -EOPNOTSUPP;
 
        if (flags & (MSG_OOB))
                return -EOPNOTSUPP;
@@ -205,8 +254,10 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                copied = len;
        }
 
                copied = len;
        }
 
-       skb->h.raw = skb->data;
+       skb_reset_transport_header(skb);
        err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
        err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+       if (err == 0)
+               sock_recv_timestamp(msg, sk, skb);
 
        skb_free_datagram(sk, skb);
 
 
        skb_free_datagram(sk, skb);
 
@@ -221,7 +272,9 @@ static inline unsigned int bt_accept_poll(struct sock *parent)
 
        list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
                sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
 
        list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
                sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
-               if (sk->sk_state == BT_CONNECTED)
+               if (sk->sk_state == BT_CONNECTED ||
+                                       (bt_sk(parent)->defer_setup &&
+                                               sk->sk_state == BT_CONNECT2))
                        return POLLIN | POLLRDNORM;
        }
 
                        return POLLIN | POLLRDNORM;
        }
 
@@ -243,10 +296,13 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
        if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
                mask |= POLLERR;
 
        if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
                mask |= POLLERR;
 
+       if (sk->sk_shutdown & RCV_SHUTDOWN)
+               mask |= POLLRDHUP;
+
        if (sk->sk_shutdown == SHUTDOWN_MASK)
                mask |= POLLHUP;
 
        if (sk->sk_shutdown == SHUTDOWN_MASK)
                mask |= POLLHUP;
 
-       if (!skb_queue_empty(&sk->sk_receive_queue) || 
+       if (!skb_queue_empty(&sk->sk_receive_queue) ||
                        (sk->sk_shutdown & RCV_SHUTDOWN))
                mask |= POLLIN | POLLRDNORM;
 
                        (sk->sk_shutdown & RCV_SHUTDOWN))
                mask |= POLLIN | POLLRDNORM;
 
@@ -267,6 +323,54 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
 }
 EXPORT_SYMBOL(bt_sock_poll);
 
 }
 EXPORT_SYMBOL(bt_sock_poll);
 
+int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       struct sock *sk = sock->sk;
+       struct sk_buff *skb;
+       long amount;
+       int err;
+
+       BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg);
+
+       switch (cmd) {
+       case TIOCOUTQ:
+               if (sk->sk_state == BT_LISTEN)
+                       return -EINVAL;
+
+               amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+               if (amount < 0)
+                       amount = 0;
+               err = put_user(amount, (int __user *) arg);
+               break;
+
+       case TIOCINQ:
+               if (sk->sk_state == BT_LISTEN)
+                       return -EINVAL;
+
+               lock_sock(sk);
+               skb = skb_peek(&sk->sk_receive_queue);
+               amount = skb ? skb->len : 0;
+               release_sock(sk);
+               err = put_user(amount, (int __user *) arg);
+               break;
+
+       case SIOCGSTAMP:
+               err = sock_get_timestamp(sk, (struct timeval __user *) arg);
+               break;
+
+       case SIOCGSTAMPNS:
+               err = sock_get_timestampns(sk, (struct timespec __user *) arg);
+               break;
+
+       default:
+               err = -ENOIOCTLCMD;
+               break;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL(bt_sock_ioctl);
+
 int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
 {
        DECLARE_WAITQUEUE(wait, current);
 int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
 {
        DECLARE_WAITQUEUE(wait, current);
@@ -279,7 +383,7 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
                set_current_state(TASK_INTERRUPTIBLE);
 
                if (!timeo) {
                set_current_state(TASK_INTERRUPTIBLE);
 
                if (!timeo) {
-                       err = -EAGAIN;
+                       err = -EINPROGRESS;
                        break;
                }
 
                        break;
                }
 
@@ -292,10 +396,9 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
                timeo = schedule_timeout(timeo);
                lock_sock(sk);
 
                timeo = schedule_timeout(timeo);
                lock_sock(sk);
 
-               if (sk->sk_err) {
-                       err = sock_error(sk);
+               err = sock_error(sk);
+               if (err)
                        break;
                        break;
-               }
        }
        set_current_state(TASK_RUNNING);
        remove_wait_queue(sk->sk_sleep, &wait);
        }
        set_current_state(TASK_RUNNING);
        remove_wait_queue(sk->sk_sleep, &wait);
@@ -309,26 +412,24 @@ static struct net_proto_family bt_sock_family_ops = {
        .create = bt_sock_create,
 };
 
        .create = bt_sock_create,
 };
 
-extern int hci_sock_init(void);
-extern int hci_sock_cleanup(void);
-
-extern int bt_sysfs_init(void);
-extern int bt_sysfs_cleanup(void);
-
 static int __init bt_init(void)
 {
 static int __init bt_init(void)
 {
+       int err;
+
        BT_INFO("Core ver %s", VERSION);
 
        BT_INFO("Core ver %s", VERSION);
 
-       proc_bt = proc_mkdir("bluetooth", NULL);
-       if (proc_bt)
-               proc_bt->owner = THIS_MODULE;
+       err = bt_sysfs_init();
+       if (err < 0)
+               return err;
 
 
-       sock_register(&bt_sock_family_ops);
+       err = sock_register(&bt_sock_family_ops);
+       if (err < 0) {
+               bt_sysfs_cleanup();
+               return err;
+       }
 
        BT_INFO("HCI device and connection manager initialized");
 
 
        BT_INFO("HCI device and connection manager initialized");
 
-       bt_sysfs_init();
-
        hci_sock_init();
 
        return 0;
        hci_sock_init();
 
        return 0;
@@ -338,17 +439,15 @@ static void __exit bt_exit(void)
 {
        hci_sock_cleanup();
 
 {
        hci_sock_cleanup();
 
-       bt_sysfs_cleanup();
-
        sock_unregister(PF_BLUETOOTH);
 
        sock_unregister(PF_BLUETOOTH);
 
-       remove_proc_entry("bluetooth", NULL);
+       bt_sysfs_cleanup();
 }
 
 subsys_initcall(bt_init);
 module_exit(bt_exit);
 
 }
 
 subsys_initcall(bt_init);
 module_exit(bt_exit);
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth Core ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Bluetooth Core ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");