fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / bluetooth / rfcomm / sock.c
index 1428ce6..cb7e855 100644 (file)
  * $Id: sock.c,v 1.24 2002/10/03 01:00:34 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/sched.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/socket.h>
 #include <linux/skbuff.h>
 #include <linux/list.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
+#include <linux/device.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/rfcomm.h>
 
 #ifndef CONFIG_BT_RFCOMM_DEBUG
@@ -58,7 +57,7 @@
 #define BT_DBG(D...)
 #endif
 
-static struct proto_ops rfcomm_sock_ops;
+static const struct proto_ops rfcomm_sock_ops;
 
 static struct bt_sock_list rfcomm_sk_list = {
        .lock = RW_LOCK_UNLOCKED
@@ -97,17 +96,31 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
 
        if (err)
                sk->sk_err = err;
+
        sk->sk_state = d->state;
 
        parent = bt_sk(sk)->parent;
-       if (!parent) {
+       if (parent) {
+               if (d->state == BT_CLOSED) {
+                       sock_set_flag(sk, SOCK_ZAPPED);
+                       bt_accept_unlink(sk);
+               }
+               parent->sk_data_ready(parent, 0);
+       } else {
                if (d->state == BT_CONNECTED)
                        rfcomm_session_getaddr(d->session, &bt_sk(sk)->src, NULL);
                sk->sk_state_change(sk);
-       } else
-               parent->sk_data_ready(parent, 0);
+       }
 
        bh_unlock_sock(sk);
+
+       if (parent && sock_flag(sk, SOCK_ZAPPED)) {
+               /* We have to drop DLC lock here, otherwise
+                * rfcomm_sock_destruct() will dead lock. */
+               rfcomm_dlc_unlock(d);
+               rfcomm_sock_kill(sk);
+               rfcomm_dlc_lock(d);
+       }
 }
 
 /* ---- Socket functions ---- */
@@ -173,16 +186,13 @@ static void rfcomm_sock_destruct(struct sock *sk)
 
        rfcomm_dlc_lock(d);
        rfcomm_pi(sk)->dlc = NULL;
-       
+
        /* Detach DLC if it's owned by this socket */
        if (d->owner == sk)
                d->owner = NULL;
        rfcomm_dlc_unlock(d);
 
        rfcomm_dlc_put(d);
-
-       if (sk->sk_protinfo)
-               kfree(sk->sk_protinfo);
 }
 
 static void rfcomm_sock_cleanup_listen(struct sock *parent)
@@ -198,7 +208,7 @@ static void rfcomm_sock_cleanup_listen(struct sock *parent)
        }
 
        parent->sk_state  = BT_CLOSED;
-       parent->sk_zapped = 1;
+       sock_set_flag(parent, SOCK_ZAPPED);
 }
 
 /* Kill socket (only if zapped and orphan)
@@ -206,7 +216,7 @@ static void rfcomm_sock_cleanup_listen(struct sock *parent)
  */
 static void rfcomm_sock_kill(struct sock *sk)
 {
-       if (!sk->sk_zapped || sk->sk_socket)
+       if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
                return;
 
        BT_DBG("sk %p state %d refcnt %d", sk, sk->sk_state, atomic_read(&sk->sk_refcnt));
@@ -235,7 +245,7 @@ static void __rfcomm_sock_close(struct sock *sk)
                rfcomm_dlc_close(d, 0);
 
        default:
-               sk->sk_zapped = 1;
+               sock_set_flag(sk, SOCK_ZAPPED);
                break;
        }
 }
@@ -252,28 +262,44 @@ static void rfcomm_sock_close(struct sock *sk)
 
 static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
 {
+       struct rfcomm_pinfo *pi = rfcomm_pi(sk);
+
        BT_DBG("sk %p", sk);
 
-       if (parent) 
+       if (parent) {
                sk->sk_type = parent->sk_type;
+               pi->link_mode = rfcomm_pi(parent)->link_mode;
+       } else {
+               pi->link_mode = 0;
+       }
+
+       pi->dlc->link_mode = pi->link_mode;
 }
 
-static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio)
+static struct proto rfcomm_proto = {
+       .name           = "RFCOMM",
+       .owner          = THIS_MODULE,
+       .obj_size       = sizeof(struct rfcomm_pinfo)
+};
+
+static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, gfp_t prio)
 {
        struct rfcomm_dlc *d;
        struct sock *sk;
 
-       sk = bt_sock_alloc(sock, BTPROTO_RFCOMM, sizeof(struct rfcomm_pinfo), prio);
+       sk = sk_alloc(PF_BLUETOOTH, prio, &rfcomm_proto, 1);
        if (!sk)
                return NULL;
 
-       sk_set_owner(sk, THIS_MODULE);
+       sock_init_data(sock, sk);
+       INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
 
        d = rfcomm_dlc_alloc(prio);
        if (!d) {
                sk_free(sk);
                return NULL;
        }
+
        d->data_ready   = rfcomm_sk_data_ready;
        d->state_change = rfcomm_sk_state_change;
 
@@ -286,8 +312,10 @@ static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio)
        sk->sk_sndbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
        sk->sk_rcvbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
 
+       sock_reset_flag(sk, SOCK_ZAPPED);
+
        sk->sk_protocol = proto;
-       sk->sk_state    = BT_OPEN;
+       sk->sk_state    = BT_OPEN;
 
        bt_sock_link(&rfcomm_sk_list, sk);
 
@@ -308,7 +336,8 @@ static int rfcomm_sock_create(struct socket *sock, int protocol)
 
        sock->ops = &rfcomm_sock_ops;
 
-       if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL)))
+       sk = rfcomm_sock_alloc(sock, protocol, GFP_ATOMIC);
+       if (!sk)
                return -ENOMEM;
 
        rfcomm_sock_init(sk, NULL);
@@ -333,6 +362,11 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
                goto done;
        }
 
+       if (sk->sk_type != SOCK_STREAM) {
+               err = -EINVAL;
+               goto done;
+       }
+
        write_lock_bh(&rfcomm_sk_list.lock);
 
        if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
@@ -363,13 +397,17 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
        if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc))
                return -EINVAL;
 
-       if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
-               return -EBADFD;
+       lock_sock(sk);
 
-       if (sk->sk_type != SOCK_STREAM)
-               return -EINVAL;
+       if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
+               err = -EBADFD;
+               goto done;
+       }
 
-       lock_sock(sk);
+       if (sk->sk_type != SOCK_STREAM) {
+               err = -EINVAL;
+               goto done;
+       }
 
        sk->sk_state = BT_CONNECT;
        bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
@@ -380,11 +418,12 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
                err = bt_sock_wait_state(sk, BT_CONNECTED,
                                sock_sndtimeo(sk, flags & O_NONBLOCK));
 
+done:
        release_sock(sk);
        return err;
 }
 
-int rfcomm_sock_listen(struct socket *sock, int backlog)
+static int rfcomm_sock_listen(struct socket *sock, int backlog)
 {
        struct sock *sk = sock->sk;
        int err = 0;
@@ -398,6 +437,32 @@ int rfcomm_sock_listen(struct socket *sock, int backlog)
                goto done;
        }
 
+       if (sk->sk_type != SOCK_STREAM) {
+               err = -EINVAL;
+               goto done;
+       }
+
+       if (!rfcomm_pi(sk)->channel) {
+               bdaddr_t *src = &bt_sk(sk)->src;
+               u8 channel;
+
+               err = -EINVAL;
+
+               write_lock_bh(&rfcomm_sk_list.lock);
+
+               for (channel = 1; channel < 31; channel++)
+                       if (!__rfcomm_get_sock_by_addr(channel, src)) {
+                               rfcomm_pi(sk)->channel = channel;
+                               err = 0;
+                               break;
+                       }
+
+               write_unlock_bh(&rfcomm_sk_list.lock);
+
+               if (err < 0)
+                       goto done;
+       }
+
        sk->sk_max_ack_backlog = backlog;
        sk->sk_ack_backlog = 0;
        sk->sk_state = BT_LISTEN;
@@ -407,7 +472,7 @@ done:
        return err;
 }
 
-int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
 {
        DECLARE_WAITQUEUE(wait, current);
        struct sock *sk = sock->sk, *nsk;
@@ -421,6 +486,11 @@ int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
                goto done;
        }
 
+       if (sk->sk_type != SOCK_STREAM) {
+               err = -EINVAL;
+               goto done;
+       }
+
        timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
 
        BT_DBG("sk %p timeo %ld", sk, timeo);
@@ -487,7 +557,6 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
        struct sock *sk = sock->sk;
        struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
        struct sk_buff *skb;
-       int err;
        int sent = 0;
 
        if (msg->msg_flags & MSG_OOB)
@@ -502,6 +571,7 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
 
        while (len) {
                size_t size = min_t(size_t, len, d->mtu);
+               int err;
                
                skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
                                msg->msg_flags & MSG_DONTWAIT, &err);
@@ -512,13 +582,16 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
                if (err) {
                        kfree_skb(skb);
-                       sent = err;
+                       if (sent == 0)
+                               sent = err;
                        break;
                }
 
                err = rfcomm_dlc_send(d, skb);
                if (err < 0) {
                        kfree_skb(skb);
+                       if (sent == 0)
+                               sent = err;
                        break;
                }
 
@@ -528,7 +601,7 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
 
        release_sock(sk);
 
-       return sent ? sent : err;
+       return sent;
 }
 
 static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
@@ -539,8 +612,11 @@ static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
        for (;;) {
                set_current_state(TASK_INTERRUPTIBLE);
 
-               if (skb_queue_len(&sk->sk_receive_queue) || sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN) ||
-                               signal_pending(current) || !timeo)
+               if (!skb_queue_empty(&sk->sk_receive_queue) ||
+                   sk->sk_err ||
+                   (sk->sk_shutdown & RCV_SHUTDOWN) ||
+                   signal_pending(current) ||
+                   !timeo)
                        break;
 
                set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
@@ -637,16 +713,26 @@ out:
        return copied ? : err;
 }
 
-static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
 {
        struct sock *sk = sock->sk;
        int err = 0;
+       u32 opt;
 
        BT_DBG("sk %p", sk);
 
        lock_sock(sk);
 
        switch (optname) {
+       case RFCOMM_LM:
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               rfcomm_pi(sk)->link_mode = opt;
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;
@@ -656,10 +742,12 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
        return err;
 }
 
-static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
-       int len, err = 0; 
+       struct sock *l2cap_sk;
+       struct rfcomm_conninfo cinfo;
+       int len, err = 0;
 
        BT_DBG("sk %p", sk);
 
@@ -669,10 +757,32 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
        lock_sock(sk);
 
        switch (optname) {
+       case RFCOMM_LM:
+               if (put_user(rfcomm_pi(sk)->link_mode, (u32 __user *) optval))
+                       err = -EFAULT;
+               break;
+
+       case RFCOMM_CONNINFO:
+               if (sk->sk_state != BT_CONNECTED) {
+                       err = -ENOTCONN;
+                       break;
+               }
+
+               l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;
+
+               cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle;
+               memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3);
+
+               len = min_t(unsigned int, len, sizeof(cinfo));
+               if (copy_to_user(optval, (char *) &cinfo, len))
+                       err = -EFAULT;
+
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;
-       };
+       }
 
        release_sock(sk);
        return err;
@@ -686,7 +796,7 @@ static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned lon
        lock_sock(sk);
 
 #ifdef CONFIG_BT_RFCOMM_TTY
-       err = rfcomm_dev_ioctl(sk, cmd, arg);
+       err = rfcomm_dev_ioctl(sk, cmd, (void __user *)arg);
 #else
        err = -EOPNOTSUPP;
 #endif
@@ -753,7 +863,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
                return 0;
 
        /* Check for backlog size */
-       if (parent->sk_ack_backlog > parent->sk_max_ack_backlog) {
+       if (sk_acceptq_is_full(parent)) {
                BT_DBG("backlog full %d", parent->sk_ack_backlog); 
                goto done;
        }
@@ -779,91 +889,28 @@ done:
        return result;
 }
 
-/* ---- Proc fs support ---- */
-#ifdef CONFIG_PROC_FS
-static void *rfcomm_seq_start(struct seq_file *seq, loff_t *pos)
+static ssize_t rfcomm_sock_sysfs_show(struct class *dev, char *buf)
 {
        struct sock *sk;
        struct hlist_node *node;
-       loff_t l = *pos;
+       char *str = buf;
 
        read_lock_bh(&rfcomm_sk_list.lock);
 
-       sk_for_each(sk, node, &rfcomm_sk_list.head)
-               if (!l--)
-                       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(sk);
-}
+       sk_for_each(sk, node, &rfcomm_sk_list.head) {
+               str += sprintf(str, "%s %s %d %d\n",
+                               batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
+                               sk->sk_state, rfcomm_pi(sk)->channel);
+       }
 
-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),
-                       sk->sk_state, rfcomm_pi(sk)->channel);
-       return 0;
-}
-
-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);
-}
 
-static struct file_operations rfcomm_seq_fops = {
-       .owner   = THIS_MODULE,
-       .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 __exit rfcomm_sock_proc_cleanup(void)
-{
-        remove_proc_entry("sock", proc_bt_rfcomm);
+       return (str - buf);
 }
 
-#else /* CONFIG_PROC_FS */
+static CLASS_ATTR(rfcomm, S_IRUGO, rfcomm_sock_sysfs_show, NULL);
 
-static int  __init rfcomm_sock_proc_init(void)
-{
-        return 0;
-}
-
-static void __exit rfcomm_sock_proc_cleanup(void)
-{
-        return;
-}
-#endif /* CONFIG_PROC_FS */
-
-static struct proto_ops rfcomm_sock_ops = {
+static const struct proto_ops rfcomm_sock_ops = {
        .family         = PF_BLUETOOTH,
        .owner          = THIS_MODULE,
        .release        = rfcomm_sock_release,
@@ -889,28 +936,37 @@ static struct net_proto_family rfcomm_sock_family_ops = {
        .create         = rfcomm_sock_create
 };
 
-int  __init rfcomm_init_sockets(void)
+int __init rfcomm_init_sockets(void)
 {
        int err;
 
-       if ((err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) {
-               BT_ERR("RFCOMM socket layer registration failed. %d", err);
+       err = proto_register(&rfcomm_proto, 0);
+       if (err < 0)
                return err;
-       }
 
-       rfcomm_sock_proc_init();
+       err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops);
+       if (err < 0)
+               goto error;
+
+       if (class_create_file(bt_class, &class_attr_rfcomm) < 0)
+               BT_ERR("Failed to create RFCOMM info file");
 
        BT_INFO("RFCOMM socket layer initialized");
+
        return 0;
+
+error:
+       BT_ERR("RFCOMM socket layer registration failed");
+       proto_unregister(&rfcomm_proto);
+       return err;
 }
 
 void __exit rfcomm_cleanup_sockets(void)
 {
-       int err;
+       class_remove_file(bt_class, &class_attr_rfcomm);
 
-       rfcomm_sock_proc_cleanup();
+       if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
+               BT_ERR("RFCOMM socket layer unregistration failed");
 
-       /* Unregister socket, protocol and notifier */
-       if ((err = bt_sock_unregister(BTPROTO_RFCOMM)))
-               BT_ERR("RFCOMM socket layer unregistration failed. %d", err);
+       proto_unregister(&rfcomm_proto);
 }