]> Pileus Git - ~andy/linux/blobdiff - net/bluetooth/l2cap_sock.c
Bluetooth: Add chan->ops->defer()
[~andy/linux] / net / bluetooth / l2cap_sock.c
index a4bb27e8427e9aabaa48b90727cb23bcf5568f96..5fae2bd879a1d8c194a1288e2c24564db8d1e088 100644 (file)
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/smp.h>
 
+static struct bt_sock_list l2cap_sk_list = {
+       .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
+};
+
 static const struct proto_ops l2cap_sock_ops;
 static void l2cap_sock_init(struct sock *sk, struct sock *parent);
-static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio);
+static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
+                                    int proto, gfp_t prio);
 
 static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 {
@@ -102,7 +107,8 @@ done:
        return err;
 }
 
-static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
+static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
+                             int alen, int flags)
 {
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@@ -130,7 +136,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
        lock_sock(sk);
 
        err = bt_sock_wait_state(sk, BT_CONNECTED,
-                       sock_sndtimeo(sk, flags & O_NONBLOCK));
+                                sock_sndtimeo(sk, flags & O_NONBLOCK));
 
        release_sock(sk);
 
@@ -181,7 +187,8 @@ done:
        return err;
 }
 
-static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+static int l2cap_sock_accept(struct socket *sock, struct socket *newsock,
+                            int flags)
 {
        DECLARE_WAITQUEUE(wait, current);
        struct sock *sk = sock->sk, *nsk;
@@ -237,7 +244,8 @@ done:
        return err;
 }
 
-static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
+static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr,
+                             int *len, int peer)
 {
        struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
        struct sock *sk = sock->sk;
@@ -261,7 +269,8 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
        return 0;
 }
 
-static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
+static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
+                                    char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@@ -304,7 +313,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
                        break;
                case BT_SECURITY_HIGH:
                        opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
-                                                       L2CAP_LM_SECURE;
+                             L2CAP_LM_SECURE;
                        break;
                default:
                        opt = 0;
@@ -348,7 +357,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
        return err;
 }
 
-static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
+                                char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@@ -372,19 +382,20 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
        switch (optname) {
        case BT_SECURITY:
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
-                                       chan->chan_type != L2CAP_CHAN_RAW) {
+                   chan->chan_type != L2CAP_CHAN_RAW) {
                        err = -EINVAL;
                        break;
                }
 
                memset(&sec, 0, sizeof(sec));
-               if (chan->conn)
+               if (chan->conn) {
                        sec.level = chan->conn->hcon->sec_level;
-               else
-                       sec.level = chan->sec_level;
 
-               if (sk->sk_state == BT_CONNECTED)
-                       sec.key_size = chan->conn->hcon->enc_key_size;
+                       if (sk->sk_state == BT_CONNECTED)
+                               sec.key_size = chan->conn->hcon->enc_key_size;
+               } else {
+                       sec.level = chan->sec_level;
+               }
 
                len = min_t(unsigned int, len, sizeof(sec));
                if (copy_to_user(optval, (char *) &sec, len))
@@ -406,14 +417,14 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 
        case BT_FLUSHABLE:
                if (put_user(test_bit(FLAG_FLUSHABLE, &chan->flags),
-                                               (u32 __user *) optval))
+                            (u32 __user *) optval))
                        err = -EFAULT;
 
                break;
 
        case BT_POWER:
                if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
-                               && sk->sk_type != SOCK_RAW) {
+                   && sk->sk_type != SOCK_RAW) {
                        err = -EINVAL;
                        break;
                }
@@ -461,7 +472,8 @@ static bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu)
        return true;
 }
 
-static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
+static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
+                                    char __user *optval, unsigned int optlen)
 {
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@@ -524,6 +536,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                chan->fcs  = opts.fcs;
                chan->max_tx = opts.max_tx;
                chan->tx_win = opts.txwin_size;
+               chan->flush_to = opts.flush_to;
                break;
 
        case L2CAP_LM:
@@ -559,7 +572,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
        return err;
 }
 
-static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
+static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
+                                char __user *optval, unsigned int optlen)
 {
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@@ -582,7 +596,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
        switch (optname) {
        case BT_SECURITY:
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
-                                       chan->chan_type != L2CAP_CHAN_RAW) {
+                   chan->chan_type != L2CAP_CHAN_RAW) {
                        err = -EINVAL;
                        break;
                }
@@ -596,7 +610,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                }
 
                if (sec.level < BT_SECURITY_LOW ||
-                                       sec.level > BT_SECURITY_HIGH) {
+                   sec.level > BT_SECURITY_HIGH) {
                        err = -EINVAL;
                        break;
                }
@@ -615,14 +629,14 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                                break;
                        }
 
-                       if (smp_conn_security(conn, sec.level))
+                       if (smp_conn_security(conn->hcon, sec.level))
                                break;
                        sk->sk_state = BT_CONFIG;
                        chan->state = BT_CONFIG;
 
                /* or for ACL link */
                } else if ((sk->sk_state == BT_CONNECT2 &&
-                          test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) ||
+                           test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) ||
                           sk->sk_state == BT_CONNECTED) {
                        if (!l2cap_chan_check_security(chan))
                                set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
@@ -679,7 +693,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 
        case BT_POWER:
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
-                                       chan->chan_type != L2CAP_CHAN_RAW) {
+                   chan->chan_type != L2CAP_CHAN_RAW) {
                        err = -EINVAL;
                        break;
                }
@@ -715,7 +729,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                }
 
                if (chan->mode != L2CAP_MODE_ERTM &&
-                               chan->mode != L2CAP_MODE_STREAMING) {
+                   chan->mode != L2CAP_MODE_STREAMING) {
                        err = -EOPNOTSUPP;
                        break;
                }
@@ -732,7 +746,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
        return err;
 }
 
-static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len)
+static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+                             struct msghdr *msg, size_t len)
 {
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@@ -757,7 +772,8 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
        return err;
 }
 
-static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags)
+static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+                             struct msghdr *msg, size_t len, int flags)
 {
        struct sock *sk = sock->sk;
        struct l2cap_pinfo *pi = l2cap_pi(sk);
@@ -823,7 +839,7 @@ static void l2cap_sock_kill(struct sock *sk)
 
        /* Kill poor orphan */
 
-       l2cap_chan_destroy(l2cap_pi(sk)->chan);
+       l2cap_chan_put(l2cap_pi(sk)->chan);
        sock_set_flag(sk, SOCK_DEAD);
        sock_put(sk);
 }
@@ -861,7 +877,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
 
                if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
                        err = bt_sock_wait_state(sk, BT_CLOSED,
-                                                       sk->sk_lingertime);
+                                                sk->sk_lingertime);
        }
 
        if (!err && sk->sk_err)
@@ -886,6 +902,8 @@ static int l2cap_sock_release(struct socket *sock)
        if (!sk)
                return 0;
 
+       bt_sock_unlink(&l2cap_sk_list, sk);
+
        err = l2cap_sock_shutdown(sock, 2);
 
        sock_orphan(sk);
@@ -923,7 +941,7 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
        }
 
        sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
-                                                               GFP_ATOMIC);
+                             GFP_ATOMIC);
        if (!sk)
                return NULL;
 
@@ -931,6 +949,8 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
 
        l2cap_sock_init(sk, parent);
 
+       bt_accept_enqueue(parent, sk);
+
        return l2cap_pi(sk)->chan;
 }
 
@@ -1061,6 +1081,15 @@ static void l2cap_sock_ready_cb(struct l2cap_chan *chan)
        release_sock(sk);
 }
 
+static void l2cap_sock_defer_cb(struct l2cap_chan *chan)
+{
+       struct sock *sk = chan->data;
+       struct sock *parent = bt_sk(sk)->parent;
+
+       if (parent)
+               parent->sk_data_ready(parent, 0);
+}
+
 static struct l2cap_ops l2cap_chan_ops = {
        .name           = "L2CAP Socket Interface",
        .new_connection = l2cap_sock_new_connection_cb,
@@ -1069,6 +1098,7 @@ static struct l2cap_ops l2cap_chan_ops = {
        .teardown       = l2cap_sock_teardown_cb,
        .state_change   = l2cap_sock_state_change_cb,
        .ready          = l2cap_sock_ready_cb,
+       .defer          = l2cap_sock_defer_cb,
        .alloc_skb      = l2cap_sock_alloc_skb_cb,
 };
 
@@ -1076,7 +1106,8 @@ static void l2cap_sock_destruct(struct sock *sk)
 {
        BT_DBG("sk %p", sk);
 
-       l2cap_chan_put(l2cap_pi(sk)->chan);
+       if (l2cap_pi(sk)->chan)
+               l2cap_chan_put(l2cap_pi(sk)->chan);
        if (l2cap_pi(sk)->rx_busy_skb) {
                kfree_skb(l2cap_pi(sk)->rx_busy_skb);
                l2cap_pi(sk)->rx_busy_skb = NULL;
@@ -1152,7 +1183,8 @@ static struct proto l2cap_proto = {
        .obj_size       = sizeof(struct l2cap_pinfo)
 };
 
-static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
+static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
+                                    int proto, gfp_t prio)
 {
        struct sock *sk;
        struct l2cap_chan *chan;
@@ -1174,7 +1206,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
 
        chan = l2cap_chan_create();
        if (!chan) {
-               l2cap_sock_kill(sk);
+               sk_free(sk);
                return NULL;
        }
 
@@ -1197,7 +1229,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
        sock->state = SS_UNCONNECTED;
 
        if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM &&
-                       sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
+           sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
                return -ESOCKTNOSUPPORT;
 
        if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
@@ -1210,6 +1242,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
                return -ENOMEM;
 
        l2cap_sock_init(sk, NULL);
+       bt_sock_link(&l2cap_sk_list, sk);
        return 0;
 }
 
@@ -1248,21 +1281,31 @@ int __init l2cap_init_sockets(void)
                return err;
 
        err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
-       if (err < 0)
+       if (err < 0) {
+               BT_ERR("L2CAP socket registration failed");
+               goto error;
+       }
+
+       err = bt_procfs_init(THIS_MODULE, &init_net, "l2cap", &l2cap_sk_list,
+                            NULL);
+       if (err < 0) {
+               BT_ERR("Failed to create L2CAP proc file");
+               bt_sock_unregister(BTPROTO_L2CAP);
                goto error;
+       }
 
        BT_INFO("L2CAP socket layer initialized");
 
        return 0;
 
 error:
-       BT_ERR("L2CAP socket registration failed");
        proto_unregister(&l2cap_proto);
        return err;
 }
 
 void l2cap_cleanup_sockets(void)
 {
+       bt_procfs_cleanup(&init_net, "l2cap");
        if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
                BT_ERR("L2CAP socket unregistration failed");