Bluetooth: Add support for deferring RFCOMM connection setup
[safe/jmp/linux-2.6] / net / bluetooth / rfcomm / sock.c
index 6c34261..d37a829 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    RFCOMM implementation for Linux Bluetooth stack (BlueZ).
    Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
    Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
    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.
 
-   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.
 */
 
 /*
  * RFCOMM sockets.
- *
- * $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 <net/bluetooth/l2cap.h>
 #include <net/bluetooth/rfcomm.h>
 
-#ifndef CONFIG_BT_RFCOMM_DEBUG
-#undef  BT_DBG
-#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
+       .lock = __RW_LOCK_UNLOCKED(rfcomm_sk_list.lock)
 };
 
 static void rfcomm_sock_close(struct sock *sk);
@@ -131,7 +123,7 @@ static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src)
        struct hlist_node *node;
 
        sk_for_each(sk, node, &rfcomm_sk_list.head) {
-               if (rfcomm_pi(sk)->channel == channel && 
+               if (rfcomm_pi(sk)->channel == channel &&
                                !bacmp(&bt_sk(sk)->src, src))
                        break;
        }
@@ -270,8 +262,10 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
        if (parent) {
                sk->sk_type = parent->sk_type;
                pi->link_mode = rfcomm_pi(parent)->link_mode;
+               pi->dlc->defer_setup = bt_sk(parent)->defer_setup;
        } else {
                pi->link_mode = 0;
+               pi->dlc->defer_setup = 0;
        }
 
        pi->dlc->link_mode = pi->link_mode;
@@ -283,12 +277,12 @@ static struct proto rfcomm_proto = {
        .obj_size       = sizeof(struct rfcomm_pinfo)
 };
 
-static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, gfp_t prio)
+static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
 {
        struct rfcomm_dlc *d;
        struct sock *sk;
 
-       sk = sk_alloc(PF_BLUETOOTH, prio, &rfcomm_proto, 1);
+       sk = sk_alloc(net, PF_BLUETOOTH, prio, &rfcomm_proto);
        if (!sk)
                return NULL;
 
@@ -310,13 +304,13 @@ static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, gfp_t prio
        sk->sk_destruct = rfcomm_sock_destruct;
        sk->sk_sndtimeo = RFCOMM_CONN_TIMEOUT;
 
-       sk->sk_sndbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
-       sk->sk_rcvbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+       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);
 
@@ -324,7 +318,7 @@ static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, gfp_t prio
        return sk;
 }
 
-static int rfcomm_sock_create(struct socket *sock, int protocol)
+static int rfcomm_sock_create(struct net *net, struct socket *sock, int protocol)
 {
        struct sock *sk;
 
@@ -337,7 +331,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(net, sock, protocol, GFP_ATOMIC);
+       if (!sk)
                return -ENOMEM;
 
        rfcomm_sock_init(sk, NULL);
@@ -413,6 +408,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
        bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
        rfcomm_pi(sk)->channel = sa->rc_channel;
 
+       d->link_mode = rfcomm_pi(sk)->link_mode;
+
        err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
        if (!err)
                err = bt_sock_wait_state(sk, BT_CONNECTED,
@@ -557,9 +554,11 @@ 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 (test_bit(RFCOMM_DEFER_SETUP, &d->flags))
+               return -ENOTCONN;
+
        if (msg->msg_flags & MSG_OOB)
                return -EOPNOTSUPP;
 
@@ -572,23 +571,30 @@ 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);
-               if (!skb)
+               if (!skb) {
+                       if (sent == 0)
+                               sent = err;
                        break;
+               }
                skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
 
                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;
                }
 
@@ -598,7 +604,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)
@@ -632,16 +638,22 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                               struct msghdr *msg, size_t size, int flags)
 {
        struct sock *sk = sock->sk;
+       struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
        int err = 0;
        size_t target, copied = 0;
        long timeo;
 
+       if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
+               rfcomm_dlc_accept(d);
+               return 0;
+       }
+
        if (flags & MSG_OOB)
                return -EOPNOTSUPP;
 
        msg->msg_namelen = 0;
 
-       BT_DBG("sk %p size %d", sk, size);
+       BT_DBG("sk %p size %zu", sk, size);
 
        lock_sock(sk);
 
@@ -685,6 +697,8 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                copied += chunk;
                size   -= chunk;
 
+               sock_recv_timestamp(msg, sk, skb);
+
                if (!(flags & MSG_PEEK)) {
                        atomic_sub(chunk, &sk->sk_rmem_alloc);
 
@@ -710,7 +724,7 @@ out:
        return copied ? : err;
 }
 
-static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
+static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, int optlen)
 {
        struct sock *sk = sock->sk;
        int err = 0;
@@ -739,7 +753,44 @@ 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 __user *optval, int __user *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);
+
+       if (level == SOL_RFCOMM)
+               return rfcomm_sock_setsockopt_old(sock, optname, optval, optlen);
+
+       lock_sock(sk);
+
+       switch (optname) {
+       case BT_DEFER_SETUP:
+               if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               bt_sk(sk)->defer_setup = opt;
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+       return err;
+}
+
+static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        struct sock *l2cap_sk;
@@ -760,7 +811,8 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
                break;
 
        case RFCOMM_CONNINFO:
-               if (sk->sk_state != BT_CONNECTED) {
+               if (sk->sk_state != BT_CONNECTED &&
+                                       !rfcomm_pi(sk)->dlc->defer_setup) {
                        err = -ENOTCONN;
                        break;
                }
@@ -785,20 +837,61 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
        return err;
 }
 
-static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
-       int err;
+       int len, err = 0;
+
+       BT_DBG("sk %p", sk);
+
+       if (level == SOL_RFCOMM)
+               return rfcomm_sock_getsockopt_old(sock, optname, optval, optlen);
+
+       if (get_user(len, optlen))
+               return -EFAULT;
 
        lock_sock(sk);
 
+       switch (optname) {
+       case BT_DEFER_SETUP:
+               if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
+                       err = -EFAULT;
+
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+       return err;
+}
+
+static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       struct sock *sk __maybe_unused = sock->sk;
+       int err;
+
+       BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg);
+
+       err = bt_sock_ioctl(sock, cmd, arg);
+
+       if (err == -ENOIOCTLCMD) {
 #ifdef CONFIG_BT_RFCOMM_TTY
-       err = rfcomm_dev_ioctl(sk, cmd, (void __user *)arg);
+               lock_sock(sk);
+               err = rfcomm_dev_ioctl(sk, cmd, (void __user *) arg);
+               release_sock(sk);
 #else
-       err = -EOPNOTSUPP;
+               err = -EOPNOTSUPP;
 #endif
+       }
 
-       release_sock(sk);
        return err;
 }
 
@@ -840,7 +933,7 @@ static int rfcomm_sock_release(struct socket *sock)
        return err;
 }
 
-/* ---- RFCOMM core layer callbacks ---- 
+/* ---- RFCOMM core layer callbacks ----
  *
  * called under rfcomm_lock()
  */
@@ -861,11 +954,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
 
        /* Check for backlog size */
        if (sk_acceptq_is_full(parent)) {
-               BT_DBG("backlog full %d", parent->sk_ack_backlog); 
+               BT_DBG("backlog full %d", parent->sk_ack_backlog);
                goto done;
        }
 
-       sk = rfcomm_sock_alloc(NULL, BTPROTO_RFCOMM, GFP_ATOMIC);
+       sk = rfcomm_sock_alloc(sock_net(parent), NULL, BTPROTO_RFCOMM, GFP_ATOMIC);
        if (!sk)
                goto done;
 
@@ -883,6 +976,10 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
 
 done:
        bh_unlock_sock(parent);
+
+       if (bt_sk(parent)->defer_setup)
+               parent->sk_state_change(parent);
+
        return result;
 }
 
@@ -907,7 +1004,7 @@ static ssize_t rfcomm_sock_sysfs_show(struct class *dev, char *buf)
 
 static CLASS_ATTR(rfcomm, S_IRUGO, rfcomm_sock_sysfs_show, NULL);
 
-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,
@@ -945,7 +1042,8 @@ int __init rfcomm_init_sockets(void)
        if (err < 0)
                goto error;
 
-       class_create_file(&bt_class, &class_attr_rfcomm);
+       if (class_create_file(bt_class, &class_attr_rfcomm) < 0)
+               BT_ERR("Failed to create RFCOMM info file");
 
        BT_INFO("RFCOMM socket layer initialized");
 
@@ -959,7 +1057,7 @@ error:
 
 void __exit rfcomm_cleanup_sockets(void)
 {
-       class_remove_file(&bt_class, &class_attr_rfcomm);
+       class_remove_file(bt_class, &class_attr_rfcomm);
 
        if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
                BT_ERR("RFCOMM socket layer unregistration failed");