Bluetooth: notify userspace of security level change
[linux-flexiantxendom0-3.2.10.git] / net / bluetooth / l2cap_core.c
index a50610b..6f9c25b 100644 (file)
@@ -3,6 +3,7 @@
    Copyright (C) 2000-2001 Qualcomm Incorporated
    Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
    Copyright (C) 2010 Google Inc.
+   Copyright (C) 2011 ProFUSION Embedded Systems
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -48,7 +49,6 @@
 #include <linux/crc16.h>
 #include <net/sock.h>
 
-#include <asm/system.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -56,8 +56,7 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/smp.h>
 
-int disable_ertm;
-int enable_hs;
+bool disable_ertm;
 
 static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
 static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
@@ -73,21 +72,8 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
 static void l2cap_send_disconn_req(struct l2cap_conn *conn,
                                struct l2cap_chan *chan, int err);
 
-static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
-
 /* ---- L2CAP channels ---- */
 
-static inline void chan_hold(struct l2cap_chan *c)
-{
-       atomic_inc(&c->refcnt);
-}
-
-static inline void chan_put(struct l2cap_chan *c)
-{
-       if (atomic_dec_and_test(&c->refcnt))
-               kfree(c);
-}
-
 static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
 {
        struct l2cap_chan *c;
@@ -97,7 +83,6 @@ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16
                        return c;
        }
        return NULL;
-
 }
 
 static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
@@ -117,11 +102,10 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci
 {
        struct l2cap_chan *c;
 
-       read_lock(&conn->chan_lock);
+       mutex_lock(&conn->chan_lock);
        c = __l2cap_get_chan_by_scid(conn, cid);
-       if (c)
-               bh_lock_sock(c->sk);
-       read_unlock(&conn->chan_lock);
+       mutex_unlock(&conn->chan_lock);
+
        return c;
 }
 
@@ -140,11 +124,10 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn
 {
        struct l2cap_chan *c;
 
-       read_lock(&conn->chan_lock);
+       mutex_lock(&conn->chan_lock);
        c = __l2cap_get_chan_by_ident(conn, ident);
-       if (c)
-               bh_lock_sock(c->sk);
-       read_unlock(&conn->chan_lock);
+       mutex_unlock(&conn->chan_lock);
+
        return c;
 }
 
@@ -154,19 +137,16 @@ static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
 
        list_for_each_entry(c, &chan_list, global_l) {
                if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
-                       goto found;
+                       return c;
        }
-
-       c = NULL;
-found:
-       return c;
+       return NULL;
 }
 
 int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
 {
        int err;
 
-       write_lock_bh(&chan_list_lock);
+       write_lock(&chan_list_lock);
 
        if (psm && __l2cap_global_chan_by_addr(psm, src)) {
                err = -EADDRINUSE;
@@ -191,17 +171,17 @@ int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
        }
 
 done:
-       write_unlock_bh(&chan_list_lock);
+       write_unlock(&chan_list_lock);
        return err;
 }
 
 int l2cap_add_scid(struct l2cap_chan *chan,  __u16 scid)
 {
-       write_lock_bh(&chan_list_lock);
+       write_lock(&chan_list_lock);
 
        chan->scid = scid;
 
-       write_unlock_bh(&chan_list_lock);
+       write_unlock(&chan_list_lock);
 
        return 0;
 }
@@ -218,45 +198,51 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
        return 0;
 }
 
-static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
+static void __l2cap_state_change(struct l2cap_chan *chan, int state)
 {
-       BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
+       BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state),
+                                               state_to_string(state));
 
-       if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout)))
-               chan_hold(chan);
+       chan->state = state;
+       chan->ops->state_change(chan->data, state);
 }
 
-static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
+static void l2cap_state_change(struct l2cap_chan *chan, int state)
 {
-       BT_DBG("chan %p state %d", chan, chan->state);
+       struct sock *sk = chan->sk;
 
-       if (timer_pending(timer) && del_timer(timer))
-               chan_put(chan);
+       lock_sock(sk);
+       __l2cap_state_change(chan, state);
+       release_sock(sk);
 }
 
-static void l2cap_state_change(struct l2cap_chan *chan, int state)
+static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err)
 {
-       chan->state = state;
-       chan->ops->state_change(chan->data, state);
+       struct sock *sk = chan->sk;
+
+       sk->sk_err = err;
 }
 
-static void l2cap_chan_timeout(unsigned long arg)
+static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
 {
-       struct l2cap_chan *chan = (struct l2cap_chan *) arg;
        struct sock *sk = chan->sk;
-       int reason;
 
-       BT_DBG("chan %p state %d", chan, chan->state);
+       lock_sock(sk);
+       __l2cap_chan_set_err(chan, err);
+       release_sock(sk);
+}
 
-       bh_lock_sock(sk);
+static void l2cap_chan_timeout(struct work_struct *work)
+{
+       struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
+                                                       chan_timer.work);
+       struct l2cap_conn *conn = chan->conn;
+       int reason;
 
-       if (sock_owned_by_user(sk)) {
-               /* sk is owned by user. Try again later */
-               __set_chan_timer(chan, HZ / 5);
-               bh_unlock_sock(sk);
-               chan_put(chan);
-               return;
-       }
+       BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
+
+       mutex_lock(&conn->chan_lock);
+       l2cap_chan_lock(chan);
 
        if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
                reason = ECONNREFUSED;
@@ -268,10 +254,12 @@ static void l2cap_chan_timeout(unsigned long arg)
 
        l2cap_chan_close(chan, reason);
 
-       bh_unlock_sock(sk);
+       l2cap_chan_unlock(chan);
 
        chan->ops->close(chan->data);
-       chan_put(chan);
+       mutex_unlock(&conn->chan_lock);
+
+       l2cap_chan_put(chan);
 }
 
 struct l2cap_chan *l2cap_chan_create(struct sock *sk)
@@ -282,13 +270,15 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
        if (!chan)
                return NULL;
 
+       mutex_init(&chan->lock);
+
        chan->sk = sk;
 
-       write_lock_bh(&chan_list_lock);
+       write_lock(&chan_list_lock);
        list_add(&chan->global_l, &chan_list);
-       write_unlock_bh(&chan_list_lock);
+       write_unlock(&chan_list_lock);
 
-       setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
+       INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
 
        chan->state = BT_OPEN;
 
@@ -301,14 +291,14 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
 
 void l2cap_chan_destroy(struct l2cap_chan *chan)
 {
-       write_lock_bh(&chan_list_lock);
+       write_lock(&chan_list_lock);
        list_del(&chan->global_l);
-       write_unlock_bh(&chan_list_lock);
+       write_unlock(&chan_list_lock);
 
-       chan_put(chan);
+       l2cap_chan_put(chan);
 }
 
-static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 {
        BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
                        chan->psm, chan->dcid);
@@ -317,7 +307,8 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 
        chan->conn = conn;
 
-       if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
+       switch (chan->chan_type) {
+       case L2CAP_CHAN_CONN_ORIENTED:
                if (conn->hcon->type == LE_LINK) {
                        /* LE connection */
                        chan->omtu = L2CAP_LE_DEFAULT_MTU;
@@ -328,12 +319,16 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
                        chan->scid = l2cap_alloc_cid(conn);
                        chan->omtu = L2CAP_DEFAULT_MTU;
                }
-       } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
+               break;
+
+       case L2CAP_CHAN_CONN_LESS:
                /* Connectionless socket */
                chan->scid = L2CAP_CID_CONN_LESS;
                chan->dcid = L2CAP_CID_CONN_LESS;
                chan->omtu = L2CAP_DEFAULT_MTU;
-       } else {
+               break;
+
+       default:
                /* Raw socket can send/recv signalling messages only */
                chan->scid = L2CAP_CID_SIGNALING;
                chan->dcid = L2CAP_CID_SIGNALING;
@@ -347,13 +342,18 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
        chan->local_acc_lat     = L2CAP_DEFAULT_ACC_LAT;
        chan->local_flush_to    = L2CAP_DEFAULT_FLUSH_TO;
 
-       chan_hold(chan);
+       l2cap_chan_hold(chan);
 
        list_add(&chan->list, &conn->chan_l);
 }
 
-/* Delete channel.
- * Must be called on the locked socket. */
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+{
+       mutex_lock(&conn->chan_lock);
+       __l2cap_chan_add(conn, chan);
+       mutex_unlock(&conn->chan_lock);
+}
+
 static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 {
        struct sock *sk = chan->sk;
@@ -366,20 +366,21 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 
        if (conn) {
                /* Delete from channel list */
-               write_lock_bh(&conn->chan_lock);
                list_del(&chan->list);
-               write_unlock_bh(&conn->chan_lock);
-               chan_put(chan);
+
+               l2cap_chan_put(chan);
 
                chan->conn = NULL;
                hci_conn_put(conn->hcon);
        }
 
-       l2cap_state_change(chan, BT_CLOSED);
+       lock_sock(sk);
+
+       __l2cap_state_change(chan, BT_CLOSED);
        sock_set_flag(sk, SOCK_ZAPPED);
 
        if (err)
-               sk->sk_err = err;
+               __l2cap_chan_set_err(chan, err);
 
        if (parent) {
                bt_accept_unlink(sk);
@@ -387,6 +388,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
        } else
                sk->sk_state_change(sk);
 
+       release_sock(sk);
+
        if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
                        test_bit(CONF_INPUT_DONE, &chan->conf_state)))
                return;
@@ -418,10 +421,12 @@ static void l2cap_chan_cleanup_listen(struct sock *parent)
        /* Close not yet accepted channels */
        while ((sk = bt_accept_dequeue(parent, NULL))) {
                struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+
+               l2cap_chan_lock(chan);
                __clear_chan_timer(chan);
-               lock_sock(sk);
                l2cap_chan_close(chan, ECONNRESET);
-               release_sock(sk);
+               l2cap_chan_unlock(chan);
+
                chan->ops->close(chan->data);
        }
 }
@@ -431,14 +436,17 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
        struct l2cap_conn *conn = chan->conn;
        struct sock *sk = chan->sk;
 
-       BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
+       BT_DBG("chan %p state %s sk %p", chan,
+                                       state_to_string(chan->state), sk);
 
        switch (chan->state) {
        case BT_LISTEN:
+               lock_sock(sk);
                l2cap_chan_cleanup_listen(sk);
 
-               l2cap_state_change(chan, BT_CLOSED);
+               __l2cap_state_change(chan, BT_CLOSED);
                sock_set_flag(sk, SOCK_ZAPPED);
+               release_sock(sk);
                break;
 
        case BT_CONNECTED:
@@ -481,7 +489,9 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
                break;
 
        default:
+               lock_sock(sk);
                sock_set_flag(sk, SOCK_ZAPPED);
+               release_sock(sk);
                break;
        }
 }
@@ -518,7 +528,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
 }
 
 /* Service level security */
-static inline int l2cap_check_security(struct l2cap_chan *chan)
+int l2cap_chan_check_security(struct l2cap_chan *chan)
 {
        struct l2cap_conn *conn = chan->conn;
        __u8 auth_type;
@@ -538,14 +548,14 @@ static u8 l2cap_get_ident(struct l2cap_conn *conn)
         *  200 - 254 are used by utilities like l2ping, etc.
         */
 
-       spin_lock_bh(&conn->lock);
+       spin_lock(&conn->lock);
 
        if (++conn->tx_ident > 128)
                conn->tx_ident = 1;
 
        id = conn->tx_ident;
 
-       spin_unlock_bh(&conn->lock);
+       spin_unlock(&conn->lock);
 
        return id;
 }
@@ -656,6 +666,21 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
        return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
 }
 
+static void l2cap_send_conn_req(struct l2cap_chan *chan)
+{
+       struct l2cap_conn *conn = chan->conn;
+       struct l2cap_conn_req req;
+
+       req.scid = cpu_to_le16(chan->scid);
+       req.psm  = chan->psm;
+
+       chan->ident = l2cap_get_ident(conn);
+
+       set_bit(CONF_CONNECT_PEND, &chan->conf_state);
+
+       l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
+}
+
 static void l2cap_do_start(struct l2cap_chan *chan)
 {
        struct l2cap_conn *conn = chan->conn;
@@ -664,18 +689,9 @@ static void l2cap_do_start(struct l2cap_chan *chan)
                if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
                        return;
 
-               if (l2cap_check_security(chan) &&
-                               __l2cap_no_conn_pending(chan)) {
-                       struct l2cap_conn_req req;
-                       req.scid = cpu_to_le16(chan->scid);
-                       req.psm  = chan->psm;
-
-                       chan->ident = l2cap_get_ident(conn);
-                       set_bit(CONF_CONNECT_PEND, &chan->conf_state);
-
-                       l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
-                                                       sizeof(req), &req);
-               }
+               if (l2cap_chan_check_security(chan) &&
+                               __l2cap_no_conn_pending(chan))
+                       l2cap_send_conn_req(chan);
        } else {
                struct l2cap_info_req req;
                req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
@@ -683,8 +699,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
                conn->info_ident = l2cap_get_ident(conn);
 
-               mod_timer(&conn->info_timer, jiffies +
-                                       msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
+               schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
 
                l2cap_send_cmd(conn, conn->info_ident,
                                        L2CAP_INFO_REQ, sizeof(req), &req);
@@ -709,14 +724,12 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
 
 static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
 {
-       struct sock *sk;
+       struct sock *sk = chan->sk;
        struct l2cap_disconn_req req;
 
        if (!conn)
                return;
 
-       sk = chan->sk;
-
        if (chan->mode == L2CAP_MODE_ERTM) {
                __clear_retrans_timer(chan);
                __clear_monitor_timer(chan);
@@ -728,8 +741,10 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
        l2cap_send_cmd(conn, l2cap_get_ident(conn),
                        L2CAP_DISCONN_REQ, sizeof(req), &req);
 
-       l2cap_state_change(chan, BT_DISCONN);
-       sk->sk_err = err;
+       lock_sock(sk);
+       __l2cap_state_change(chan, BT_DISCONN);
+       __l2cap_chan_set_err(chan, err);
+       release_sock(sk);
 }
 
 /* ---- L2CAP connections ---- */
@@ -739,47 +754,34 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 
        BT_DBG("conn %p", conn);
 
-       read_lock(&conn->chan_lock);
+       mutex_lock(&conn->chan_lock);
 
        list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
                struct sock *sk = chan->sk;
 
-               bh_lock_sock(sk);
+               l2cap_chan_lock(chan);
 
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
-                       bh_unlock_sock(sk);
+                       l2cap_chan_unlock(chan);
                        continue;
                }
 
                if (chan->state == BT_CONNECT) {
-                       struct l2cap_conn_req req;
-
-                       if (!l2cap_check_security(chan) ||
+                       if (!l2cap_chan_check_security(chan) ||
                                        !__l2cap_no_conn_pending(chan)) {
-                               bh_unlock_sock(sk);
+                               l2cap_chan_unlock(chan);
                                continue;
                        }
 
                        if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
                                        && test_bit(CONF_STATE2_DEVICE,
                                        &chan->conf_state)) {
-                               /* l2cap_chan_close() calls list_del(chan)
-                                * so release the lock */
-                               read_unlock(&conn->chan_lock);
                                l2cap_chan_close(chan, ECONNRESET);
-                               read_lock(&conn->chan_lock);
-                               bh_unlock_sock(sk);
+                               l2cap_chan_unlock(chan);
                                continue;
                        }
 
-                       req.scid = cpu_to_le16(chan->scid);
-                       req.psm  = chan->psm;
-
-                       chan->ident = l2cap_get_ident(conn);
-                       set_bit(CONF_CONNECT_PEND, &chan->conf_state);
-
-                       l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
-                                                       sizeof(req), &req);
+                       l2cap_send_conn_req(chan);
 
                } else if (chan->state == BT_CONNECT2) {
                        struct l2cap_conn_rsp rsp;
@@ -787,7 +789,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                        rsp.scid = cpu_to_le16(chan->dcid);
                        rsp.dcid = cpu_to_le16(chan->scid);
 
-                       if (l2cap_check_security(chan)) {
+                       if (l2cap_chan_check_security(chan)) {
+                               lock_sock(sk);
                                if (bt_sk(sk)->defer_setup) {
                                        struct sock *parent = bt_sk(sk)->parent;
                                        rsp.result = cpu_to_le16(L2CAP_CR_PEND);
@@ -796,10 +799,11 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                                                parent->sk_data_ready(parent, 0);
 
                                } else {
-                                       l2cap_state_change(chan, BT_CONFIG);
+                                       __l2cap_state_change(chan, BT_CONFIG);
                                        rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
                                        rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
                                }
+                               release_sock(sk);
                        } else {
                                rsp.result = cpu_to_le16(L2CAP_CR_PEND);
                                rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
@@ -810,7 +814,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 
                        if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
                                        rsp.result != L2CAP_CR_SUCCESS) {
-                               bh_unlock_sock(sk);
+                               l2cap_chan_unlock(chan);
                                continue;
                        }
 
@@ -820,10 +824,10 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                        chan->num_conf_req++;
                }
 
-               bh_unlock_sock(sk);
+               l2cap_chan_unlock(chan);
        }
 
-       read_unlock(&conn->chan_lock);
+       mutex_unlock(&conn->chan_lock);
 }
 
 /* Find socket with cid and source bdaddr.
@@ -874,7 +878,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
        parent = pchan->sk;
 
-       bh_lock_sock(parent);
+       lock_sock(parent);
 
        /* Check for backlog size */
        if (sk_acceptq_is_full(parent)) {
@@ -888,8 +892,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
        sk = chan->sk;
 
-       write_lock_bh(&conn->chan_lock);
-
        hci_conn_hold(conn->hcon);
 
        bacpy(&bt_sk(sk)->src, conn->src);
@@ -897,34 +899,38 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
        bt_accept_enqueue(parent, sk);
 
-       __l2cap_chan_add(conn, chan);
+       l2cap_chan_add(conn, chan);
 
        __set_chan_timer(chan, sk->sk_sndtimeo);
 
-       l2cap_state_change(chan, BT_CONNECTED);
+       __l2cap_state_change(chan, BT_CONNECTED);
        parent->sk_data_ready(parent, 0);
 
-       write_unlock_bh(&conn->chan_lock);
-
 clean:
-       bh_unlock_sock(parent);
+       release_sock(parent);
 }
 
-static void l2cap_chan_ready(struct sock *sk)
+static void l2cap_chan_ready(struct l2cap_chan *chan)
 {
-       struct l2cap_chan *chan = l2cap_pi(sk)->chan;
-       struct sock *parent = bt_sk(sk)->parent;
+       struct sock *sk = chan->sk;
+       struct sock *parent;
+
+       lock_sock(sk);
+
+       parent = bt_sk(sk)->parent;
 
        BT_DBG("sk %p, parent %p", sk, parent);
 
        chan->conf_state = 0;
        __clear_chan_timer(chan);
 
-       l2cap_state_change(chan, BT_CONNECTED);
+       __l2cap_state_change(chan, BT_CONNECTED);
        sk->sk_state_change(sk);
 
        if (parent)
                parent->sk_data_ready(parent, 0);
+
+       release_sock(sk);
 }
 
 static void l2cap_conn_ready(struct l2cap_conn *conn)
@@ -939,29 +945,31 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
        if (conn->hcon->out && conn->hcon->type == LE_LINK)
                smp_conn_security(conn, conn->hcon->pending_sec_level);
 
-       read_lock(&conn->chan_lock);
+       mutex_lock(&conn->chan_lock);
 
        list_for_each_entry(chan, &conn->chan_l, list) {
-               struct sock *sk = chan->sk;
 
-               bh_lock_sock(sk);
+               l2cap_chan_lock(chan);
 
                if (conn->hcon->type == LE_LINK) {
                        if (smp_conn_security(conn, chan->sec_level))
-                               l2cap_chan_ready(sk);
+                               l2cap_chan_ready(chan);
 
                } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
+                       struct sock *sk = chan->sk;
                        __clear_chan_timer(chan);
-                       l2cap_state_change(chan, BT_CONNECTED);
+                       lock_sock(sk);
+                       __l2cap_state_change(chan, BT_CONNECTED);
                        sk->sk_state_change(sk);
+                       release_sock(sk);
 
                } else if (chan->state == BT_CONNECT)
                        l2cap_do_start(chan);
 
-               bh_unlock_sock(sk);
+               l2cap_chan_unlock(chan);
        }
 
-       read_unlock(&conn->chan_lock);
+       mutex_unlock(&conn->chan_lock);
 }
 
 /* Notify sockets that we cannot guaranty reliability anymore */
@@ -971,21 +979,20 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
 
        BT_DBG("conn %p", conn);
 
-       read_lock(&conn->chan_lock);
+       mutex_lock(&conn->chan_lock);
 
        list_for_each_entry(chan, &conn->chan_l, list) {
-               struct sock *sk = chan->sk;
-
                if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
-                       sk->sk_err = err;
+                       __l2cap_chan_set_err(chan, err);
        }
 
-       read_unlock(&conn->chan_lock);
+       mutex_unlock(&conn->chan_lock);
 }
 
-static void l2cap_info_timeout(unsigned long arg)
+static void l2cap_info_timeout(struct work_struct *work)
 {
-       struct l2cap_conn *conn = (void *) arg;
+       struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
+                                                       info_timer.work);
 
        conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
        conn->info_ident = 0;
@@ -997,7 +1004,6 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 {
        struct l2cap_conn *conn = hcon->l2cap_data;
        struct l2cap_chan *chan, *l;
-       struct sock *sk;
 
        if (!conn)
                return;
@@ -1006,22 +1012,28 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 
        kfree_skb(conn->rx_skb);
 
+       mutex_lock(&conn->chan_lock);
+
        /* Kill channels */
        list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
-               sk = chan->sk;
-               bh_lock_sock(sk);
+               l2cap_chan_lock(chan);
+
                l2cap_chan_del(chan, err);
-               bh_unlock_sock(sk);
+
+               l2cap_chan_unlock(chan);
+
                chan->ops->close(chan->data);
        }
 
+       mutex_unlock(&conn->chan_lock);
+
        hci_chan_del(conn->hchan);
 
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
-               del_timer_sync(&conn->info_timer);
+               cancel_delayed_work_sync(&conn->info_timer);
 
-       if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
-               del_timer(&conn->security_timer);
+       if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
+               cancel_delayed_work_sync(&conn->security_timer);
                smp_chan_destroy(conn);
        }
 
@@ -1029,9 +1041,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
        kfree(conn);
 }
 
-static void security_timeout(unsigned long arg)
+static void security_timeout(struct work_struct *work)
 {
-       struct l2cap_conn *conn = (void *) arg;
+       struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
+                                               security_timer.work);
 
        l2cap_conn_del(conn->hcon, ETIMEDOUT);
 }
@@ -1071,29 +1084,20 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
        conn->feat_mask = 0;
 
        spin_lock_init(&conn->lock);
-       rwlock_init(&conn->chan_lock);
+       mutex_init(&conn->chan_lock);
 
        INIT_LIST_HEAD(&conn->chan_l);
 
        if (hcon->type == LE_LINK)
-               setup_timer(&conn->security_timer, security_timeout,
-                                               (unsigned long) conn);
+               INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
        else
-               setup_timer(&conn->info_timer, l2cap_info_timeout,
-                                               (unsigned long) conn);
+               INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
 
        conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
 
        return conn;
 }
 
-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
-{
-       write_lock_bh(&conn->chan_lock);
-       __l2cap_chan_add(conn, chan);
-       write_unlock_bh(&conn->chan_lock);
-}
-
 /* ---- Socket interface ---- */
 
 /* Find socket with psm and source bdaddr.
@@ -1129,11 +1133,10 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr
        return c1;
 }
 
-int l2cap_chan_connect(struct l2cap_chan *chan)
+int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
 {
        struct sock *sk = chan->sk;
        bdaddr_t *src = &bt_sk(sk)->src;
-       bdaddr_t *dst = &bt_sk(sk)->dst;
        struct l2cap_conn *conn;
        struct hci_conn *hcon;
        struct hci_dev *hdev;
@@ -1147,7 +1150,70 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
        if (!hdev)
                return -EHOSTUNREACH;
 
-       hci_dev_lock_bh(hdev);
+       hci_dev_lock(hdev);
+
+       l2cap_chan_lock(chan);
+
+       /* PSM must be odd and lsb of upper byte must be 0 */
+       if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
+                                       chan->chan_type != L2CAP_CHAN_RAW) {
+               err = -EINVAL;
+               goto done;
+       }
+
+       if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
+               err = -EINVAL;
+               goto done;
+       }
+
+       switch (chan->mode) {
+       case L2CAP_MODE_BASIC:
+               break;
+       case L2CAP_MODE_ERTM:
+       case L2CAP_MODE_STREAMING:
+               if (!disable_ertm)
+                       break;
+               /* fall through */
+       default:
+               err = -ENOTSUPP;
+               goto done;
+       }
+
+       lock_sock(sk);
+
+       switch (sk->sk_state) {
+       case BT_CONNECT:
+       case BT_CONNECT2:
+       case BT_CONFIG:
+               /* Already connecting */
+               err = 0;
+               release_sock(sk);
+               goto done;
+
+       case BT_CONNECTED:
+               /* Already connected */
+               err = -EISCONN;
+               release_sock(sk);
+               goto done;
+
+       case BT_OPEN:
+       case BT_BOUND:
+               /* Can connect */
+               break;
+
+       default:
+               err = -EBADFD;
+               release_sock(sk);
+               goto done;
+       }
+
+       /* Set destination address and psm */
+       bacpy(&bt_sk(sk)->dst, dst);
+
+       release_sock(sk);
+
+       chan->psm = psm;
+       chan->dcid = cid;
 
        auth_type = l2cap_get_auth_type(chan);
 
@@ -1173,7 +1239,9 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
        /* Update source addr of the socket */
        bacpy(src, conn->src);
 
+       l2cap_chan_unlock(chan);
        l2cap_chan_add(conn, chan);
+       l2cap_chan_lock(chan);
 
        l2cap_state_change(chan, BT_CONNECT);
        __set_chan_timer(chan, sk->sk_sndtimeo);
@@ -1181,7 +1249,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
        if (hcon->state == BT_CONNECTED) {
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
                        __clear_chan_timer(chan);
-                       if (l2cap_check_security(chan))
+                       if (l2cap_chan_check_security(chan))
                                l2cap_state_change(chan, BT_CONNECTED);
                } else
                        l2cap_do_start(chan);
@@ -1190,7 +1258,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
        err = 0;
 
 done:
-       hci_dev_unlock_bh(hdev);
+       l2cap_chan_unlock(chan);
+       hci_dev_unlock(hdev);
        hci_dev_put(hdev);
        return err;
 }
@@ -1227,17 +1296,19 @@ int __l2cap_wait_ack(struct sock *sk)
        return err;
 }
 
-static void l2cap_monitor_timeout(unsigned long arg)
+static void l2cap_monitor_timeout(struct work_struct *work)
 {
-       struct l2cap_chan *chan = (void *) arg;
-       struct sock *sk = chan->sk;
+       struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
+                                                       monitor_timer.work);
 
        BT_DBG("chan %p", chan);
 
-       bh_lock_sock(sk);
+       l2cap_chan_lock(chan);
+
        if (chan->retry_count >= chan->remote_max_tx) {
                l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
-               bh_unlock_sock(sk);
+               l2cap_chan_unlock(chan);
+               l2cap_chan_put(chan);
                return;
        }
 
@@ -1245,24 +1316,28 @@ static void l2cap_monitor_timeout(unsigned long arg)
        __set_monitor_timer(chan);
 
        l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
-       bh_unlock_sock(sk);
+       l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 }
 
-static void l2cap_retrans_timeout(unsigned long arg)
+static void l2cap_retrans_timeout(struct work_struct *work)
 {
-       struct l2cap_chan *chan = (void *) arg;
-       struct sock *sk = chan->sk;
+       struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
+                                                       retrans_timer.work);
 
        BT_DBG("chan %p", chan);
 
-       bh_lock_sock(sk);
+       l2cap_chan_lock(chan);
+
        chan->retry_count = 1;
        __set_monitor_timer(chan);
 
        set_bit(CONN_WAIT_F, &chan->conn_state);
 
        l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
-       bh_unlock_sock(sk);
+
+       l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 }
 
 static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
@@ -1318,14 +1393,12 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
        if (!skb)
                return;
 
-       do {
-               if (bt_cb(skb)->tx_seq == tx_seq)
-                       break;
-
+       while (bt_cb(skb)->tx_seq != tx_seq) {
                if (skb_queue_is_last(&chan->tx_q, skb))
                        return;
 
-       } while ((skb = skb_queue_next(&chan->tx_q, skb)));
+               skb = skb_queue_next(&chan->tx_q, skb);
+       }
 
        if (chan->remote_max_tx &&
                        bt_cb(skb)->retries == chan->remote_max_tx) {
@@ -1405,17 +1478,19 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
 
                chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
 
-               if (bt_cb(skb)->retries == 1)
+               if (bt_cb(skb)->retries == 1) {
                        chan->unacked_frames++;
 
+                       if (!nsent++)
+                               __clear_ack_timer(chan);
+               }
+
                chan->frames_sent++;
 
                if (skb_queue_is_last(&chan->tx_q, skb))
                        chan->tx_send_head = NULL;
                else
                        chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
-
-               nsent++;
        }
 
        return nsent;
@@ -1433,7 +1508,7 @@ static int l2cap_retransmit_frames(struct l2cap_chan *chan)
        return ret;
 }
 
-static void l2cap_send_ack(struct l2cap_chan *chan)
+static void __l2cap_send_ack(struct l2cap_chan *chan)
 {
        u32 control = 0;
 
@@ -1453,6 +1528,12 @@ static void l2cap_send_ack(struct l2cap_chan *chan)
        l2cap_send_sframe(chan, control);
 }
 
+static void l2cap_send_ack(struct l2cap_chan *chan)
+{
+       __clear_ack_timer(chan);
+       __l2cap_send_ack(chan);
+}
+
 static void l2cap_send_srejtail(struct l2cap_chan *chan)
 {
        struct srej_list *tail;
@@ -1467,9 +1548,11 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan)
        l2cap_send_sframe(chan, control);
 }
 
-static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb)
+static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
+                                        struct msghdr *msg, int len,
+                                        int count, struct sk_buff *skb)
 {
-       struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
+       struct l2cap_conn *conn = chan->conn;
        struct sk_buff **frag;
        int err, sent = 0;
 
@@ -1484,7 +1567,10 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
        while (len) {
                count = min_t(unsigned int, conn->mtu, len);
 
-               *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
+               *frag = chan->ops->alloc_skb(chan, count,
+                                            msg->msg_flags & MSG_DONTWAIT,
+                                            &err);
+
                if (!*frag)
                        return err;
                if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
@@ -1505,17 +1591,18 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
                                                struct msghdr *msg, size_t len,
                                                u32 priority)
 {
-       struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
        struct sk_buff *skb;
        int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
        struct l2cap_hdr *lh;
 
-       BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
+       BT_DBG("chan %p len %d priority %u", chan, (int)len, priority);
 
        count = min_t(unsigned int, (conn->mtu - hlen), len);
-       skb = bt_skb_send_alloc(sk, count + hlen,
-                       msg->msg_flags & MSG_DONTWAIT, &err);
+
+       skb = chan->ops->alloc_skb(chan, count + hlen,
+                                  msg->msg_flags & MSG_DONTWAIT, &err);
+
        if (!skb)
                return ERR_PTR(err);
 
@@ -1527,7 +1614,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
        lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
        put_unaligned_le16(chan->psm, skb_put(skb, 2));
 
-       err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
+       err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
        if (unlikely(err < 0)) {
                kfree_skb(skb);
                return ERR_PTR(err);
@@ -1539,17 +1626,18 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
                                                struct msghdr *msg, size_t len,
                                                u32 priority)
 {
-       struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
        struct sk_buff *skb;
        int err, count, hlen = L2CAP_HDR_SIZE;
        struct l2cap_hdr *lh;
 
-       BT_DBG("sk %p len %d", sk, (int)len);
+       BT_DBG("chan %p len %d", chan, (int)len);
 
        count = min_t(unsigned int, (conn->mtu - hlen), len);
-       skb = bt_skb_send_alloc(sk, count + hlen,
-                       msg->msg_flags & MSG_DONTWAIT, &err);
+
+       skb = chan->ops->alloc_skb(chan, count + hlen,
+                                  msg->msg_flags & MSG_DONTWAIT, &err);
+
        if (!skb)
                return ERR_PTR(err);
 
@@ -1560,7 +1648,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
        lh->cid = cpu_to_le16(chan->dcid);
        lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
 
-       err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
+       err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
        if (unlikely(err < 0)) {
                kfree_skb(skb);
                return ERR_PTR(err);
@@ -1572,13 +1660,12 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
                                                struct msghdr *msg, size_t len,
                                                u32 control, u16 sdulen)
 {
-       struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
        struct sk_buff *skb;
        int err, count, hlen;
        struct l2cap_hdr *lh;
 
-       BT_DBG("sk %p len %d", sk, (int)len);
+       BT_DBG("chan %p len %d", chan, (int)len);
 
        if (!conn)
                return ERR_PTR(-ENOTCONN);
@@ -1595,8 +1682,10 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
                hlen += L2CAP_FCS_SIZE;
 
        count = min_t(unsigned int, (conn->mtu - hlen), len);
-       skb = bt_skb_send_alloc(sk, count + hlen,
-                       msg->msg_flags & MSG_DONTWAIT, &err);
+
+       skb = chan->ops->alloc_skb(chan, count + hlen,
+                                       msg->msg_flags & MSG_DONTWAIT, &err);
+
        if (!skb)
                return ERR_PTR(err);
 
@@ -1610,7 +1699,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        if (sdulen)
                put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
 
-       err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
+       err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
        if (unlikely(err < 0)) {
                kfree_skb(skb);
                return ERR_PTR(err);
@@ -1756,7 +1845,8 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
 
        BT_DBG("conn %p", conn);
 
-       read_lock(&conn->chan_lock);
+       mutex_lock(&conn->chan_lock);
+
        list_for_each_entry(chan, &conn->chan_l, list) {
                struct sock *sk = chan->sk;
                if (chan->chan_type != L2CAP_CHAN_RAW)
@@ -1772,7 +1862,8 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
                if (chan->ops->recv(chan->data, nskb))
                        kfree_skb(nskb);
        }
-       read_unlock(&conn->chan_lock);
+
+       mutex_unlock(&conn->chan_lock);
 }
 
 /* ---- L2CAP signalling commands ---- */
@@ -1906,7 +1997,7 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
 {
        struct l2cap_conf_efs efs;
 
-       switch(chan->mode) {
+       switch (chan->mode) {
        case L2CAP_MODE_ERTM:
                efs.id          = chan->local_id;
                efs.stype       = chan->local_stype;
@@ -1933,37 +2024,37 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
                                                        (unsigned long) &efs);
 }
 
-static void l2cap_ack_timeout(unsigned long arg)
+static void l2cap_ack_timeout(struct work_struct *work)
 {
-       struct l2cap_chan *chan = (void *) arg;
+       struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
+                                                       ack_timer.work);
 
-       bh_lock_sock(chan->sk);
-       l2cap_send_ack(chan);
-       bh_unlock_sock(chan->sk);
+       BT_DBG("chan %p", chan);
+
+       l2cap_chan_lock(chan);
+
+       __l2cap_send_ack(chan);
+
+       l2cap_chan_unlock(chan);
+
+       l2cap_chan_put(chan);
 }
 
 static inline void l2cap_ertm_init(struct l2cap_chan *chan)
 {
-       struct sock *sk = chan->sk;
-
        chan->expected_ack_seq = 0;
        chan->unacked_frames = 0;
        chan->buffer_seq = 0;
        chan->num_acked = 0;
        chan->frames_sent = 0;
 
-       setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
-                                                       (unsigned long) chan);
-       setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
-                                                       (unsigned long) chan);
-       setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
+       INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
+       INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
+       INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
 
        skb_queue_head_init(&chan->srej_q);
 
        INIT_LIST_HEAD(&chan->srej_l);
-
-
-       sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
 }
 
 static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
@@ -2350,7 +2441,8 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
        void *ptr = req->data;
        int type, olen;
        unsigned long val;
-       struct l2cap_conf_rfc rfc;
+       struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
+       struct l2cap_conf_efs efs;
 
        BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
 
@@ -2393,6 +2485,19 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
                                                        chan->tx_win);
                        break;
+
+               case L2CAP_CONF_EFS:
+                       if (olen == sizeof(efs))
+                               memcpy(&efs, (void *)val, olen);
+
+                       if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
+                                       efs.stype != L2CAP_SERV_NOTRAFIC &&
+                                       efs.stype != chan->local_stype)
+                               return -ECONNREFUSED;
+
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
+                                       sizeof(efs), (unsigned long) &efs);
+                       break;
                }
        }
 
@@ -2407,7 +2512,17 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
                        chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
                        chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
                        chan->mps    = le16_to_cpu(rfc.max_pdu_size);
+
+                       if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
+                               chan->local_msdu = le16_to_cpu(efs.msdu);
+                               chan->local_sdu_itime =
+                                               le32_to_cpu(efs.sdu_itime);
+                               chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
+                               chan->local_flush_to =
+                                               le32_to_cpu(efs.flush_to);
+                       }
                        break;
+
                case L2CAP_MODE_STREAMING:
                        chan->mps    = le16_to_cpu(rfc.max_pdu_size);
                }
@@ -2476,6 +2591,16 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
                }
        }
 
+       /* Use sane default values in case a misbehaving remote device
+        * did not send an RFC option.
+        */
+       rfc.mode = chan->mode;
+       rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
+       rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
+       rfc.max_pdu_size = cpu_to_le16(chan->imtu);
+
+       BT_ERR("Expected RFC option was not found, using defaults");
+
 done:
        switch (rfc.mode) {
        case L2CAP_MODE_ERTM:
@@ -2497,7 +2622,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
                                        cmd->ident == conn->info_ident) {
-               del_timer(&conn->info_timer);
+               cancel_delayed_work(&conn->info_timer);
 
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
                conn->info_ident = 0;
@@ -2530,7 +2655,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        parent = pchan->sk;
 
-       bh_lock_sock(parent);
+       mutex_lock(&conn->chan_lock);
+       lock_sock(parent);
 
        /* Check if the ACL is secure enough (if not SDP) */
        if (psm != cpu_to_le16(0x0001) &&
@@ -2554,11 +2680,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        sk = chan->sk;
 
-       write_lock_bh(&conn->chan_lock);
-
        /* Check if we already have channel with that dcid */
        if (__l2cap_get_chan_by_dcid(conn, scid)) {
-               write_unlock_bh(&conn->chan_lock);
                sock_set_flag(sk, SOCK_ZAPPED);
                chan->ops->close(chan->data);
                goto response;
@@ -2582,32 +2705,31 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
        chan->ident = cmd->ident;
 
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
-               if (l2cap_check_security(chan)) {
+               if (l2cap_chan_check_security(chan)) {
                        if (bt_sk(sk)->defer_setup) {
-                               l2cap_state_change(chan, BT_CONNECT2);
+                               __l2cap_state_change(chan, BT_CONNECT2);
                                result = L2CAP_CR_PEND;
                                status = L2CAP_CS_AUTHOR_PEND;
                                parent->sk_data_ready(parent, 0);
                        } else {
-                               l2cap_state_change(chan, BT_CONFIG);
+                               __l2cap_state_change(chan, BT_CONFIG);
                                result = L2CAP_CR_SUCCESS;
                                status = L2CAP_CS_NO_INFO;
                        }
                } else {
-                       l2cap_state_change(chan, BT_CONNECT2);
+                       __l2cap_state_change(chan, BT_CONNECT2);
                        result = L2CAP_CR_PEND;
                        status = L2CAP_CS_AUTHEN_PEND;
                }
        } else {
-               l2cap_state_change(chan, BT_CONNECT2);
+               __l2cap_state_change(chan, BT_CONNECT2);
                result = L2CAP_CR_PEND;
                status = L2CAP_CS_NO_INFO;
        }
 
-       write_unlock_bh(&conn->chan_lock);
-
 response:
-       bh_unlock_sock(parent);
+       release_sock(parent);
+       mutex_unlock(&conn->chan_lock);
 
 sendresp:
        rsp.scid   = cpu_to_le16(scid);
@@ -2623,8 +2745,7 @@ sendresp:
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
                conn->info_ident = l2cap_get_ident(conn);
 
-               mod_timer(&conn->info_timer, jiffies +
-                                       msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
+               schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
 
                l2cap_send_cmd(conn, conn->info_ident,
                                        L2CAP_INFO_REQ, sizeof(info), &info);
@@ -2647,27 +2768,36 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
        struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
        u16 scid, dcid, result, status;
        struct l2cap_chan *chan;
-       struct sock *sk;
        u8 req[128];
+       int err;
 
        scid   = __le16_to_cpu(rsp->scid);
        dcid   = __le16_to_cpu(rsp->dcid);
        result = __le16_to_cpu(rsp->result);
        status = __le16_to_cpu(rsp->status);
 
-       BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
+       BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
+                                               dcid, scid, result, status);
+
+       mutex_lock(&conn->chan_lock);
 
        if (scid) {
-               chan = l2cap_get_chan_by_scid(conn, scid);
-               if (!chan)
-                       return -EFAULT;
+               chan = __l2cap_get_chan_by_scid(conn, scid);
+               if (!chan) {
+                       err = -EFAULT;
+                       goto unlock;
+               }
        } else {
-               chan = l2cap_get_chan_by_ident(conn, cmd->ident);
-               if (!chan)
-                       return -EFAULT;
+               chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
+               if (!chan) {
+                       err = -EFAULT;
+                       goto unlock;
+               }
        }
 
-       sk = chan->sk;
+       err = 0;
+
+       l2cap_chan_lock(chan);
 
        switch (result) {
        case L2CAP_CR_SUCCESS:
@@ -2689,20 +2819,16 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
                break;
 
        default:
-               /* don't delete l2cap channel if sk is owned by user */
-               if (sock_owned_by_user(sk)) {
-                       l2cap_state_change(chan, BT_DISCONN);
-                       __clear_chan_timer(chan);
-                       __set_chan_timer(chan, HZ / 5);
-                       break;
-               }
-
                l2cap_chan_del(chan, ECONNREFUSED);
                break;
        }
 
-       bh_unlock_sock(sk);
-       return 0;
+       l2cap_chan_unlock(chan);
+
+unlock:
+       mutex_unlock(&conn->chan_lock);
+
+       return err;
 }
 
 static inline void set_default_fcs(struct l2cap_chan *chan)
@@ -2722,7 +2848,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        u16 dcid, flags;
        u8 rsp[64];
        struct l2cap_chan *chan;
-       struct sock *sk;
        int len;
 
        dcid  = __le16_to_cpu(req->dcid);
@@ -2734,7 +2859,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (!chan)
                return -ENOENT;
 
-       sk = chan->sk;
+       l2cap_chan_lock(chan);
 
        if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
                struct l2cap_cmd_rej_cid rej;
@@ -2796,7 +2921,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                if (chan->mode == L2CAP_MODE_ERTM)
                        l2cap_ertm_init(chan);
 
-               l2cap_chan_ready(sk);
+               l2cap_chan_ready(chan);
                goto unlock;
        }
 
@@ -2823,7 +2948,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        }
 
 unlock:
-       bh_unlock_sock(sk);
+       l2cap_chan_unlock(chan);
        return 0;
 }
 
@@ -2832,7 +2957,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
        u16 scid, flags, result;
        struct l2cap_chan *chan;
-       struct sock *sk;
        int len = cmd->len - sizeof(*rsp);
 
        scid   = __le16_to_cpu(rsp->scid);
@@ -2846,7 +2970,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (!chan)
                return 0;
 
-       sk = chan->sk;
+       l2cap_chan_lock(chan);
 
        switch (result) {
        case L2CAP_CONF_SUCCESS:
@@ -2905,8 +3029,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                }
 
        default:
-               sk->sk_err = ECONNRESET;
-               __set_chan_timer(chan, HZ * 5);
+               l2cap_chan_set_err(chan, ECONNRESET);
+
+               __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
                l2cap_send_disconn_req(conn, chan, ECONNRESET);
                goto done;
        }
@@ -2926,11 +3051,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                if (chan->mode ==  L2CAP_MODE_ERTM)
                        l2cap_ertm_init(chan);
 
-               l2cap_chan_ready(sk);
+               l2cap_chan_ready(chan);
        }
 
 done:
-       bh_unlock_sock(sk);
+       l2cap_chan_unlock(chan);
        return 0;
 }
 
@@ -2947,9 +3072,15 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
 
        BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
 
-       chan = l2cap_get_chan_by_scid(conn, dcid);
-       if (!chan)
+       mutex_lock(&conn->chan_lock);
+
+       chan = __l2cap_get_chan_by_scid(conn, dcid);
+       if (!chan) {
+               mutex_unlock(&conn->chan_lock);
                return 0;
+       }
+
+       l2cap_chan_lock(chan);
 
        sk = chan->sk;
 
@@ -2957,21 +3088,18 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
        rsp.scid = cpu_to_le16(chan->dcid);
        l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
 
+       lock_sock(sk);
        sk->sk_shutdown = SHUTDOWN_MASK;
-
-       /* don't delete l2cap channel if sk is owned by user */
-       if (sock_owned_by_user(sk)) {
-               l2cap_state_change(chan, BT_DISCONN);
-               __clear_chan_timer(chan);
-               __set_chan_timer(chan, HZ / 5);
-               bh_unlock_sock(sk);
-               return 0;
-       }
+       release_sock(sk);
 
        l2cap_chan_del(chan, ECONNRESET);
-       bh_unlock_sock(sk);
+
+       l2cap_chan_unlock(chan);
 
        chan->ops->close(chan->data);
+
+       mutex_unlock(&conn->chan_lock);
+
        return 0;
 }
 
@@ -2980,32 +3108,30 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
        struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
        u16 dcid, scid;
        struct l2cap_chan *chan;
-       struct sock *sk;
 
        scid = __le16_to_cpu(rsp->scid);
        dcid = __le16_to_cpu(rsp->dcid);
 
        BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
 
-       chan = l2cap_get_chan_by_scid(conn, scid);
-       if (!chan)
-               return 0;
-
-       sk = chan->sk;
+       mutex_lock(&conn->chan_lock);
 
-       /* don't delete l2cap channel if sk is owned by user */
-       if (sock_owned_by_user(sk)) {
-               l2cap_state_change(chan,BT_DISCONN);
-               __clear_chan_timer(chan);
-               __set_chan_timer(chan, HZ / 5);
-               bh_unlock_sock(sk);
+       chan = __l2cap_get_chan_by_scid(conn, scid);
+       if (!chan) {
+               mutex_unlock(&conn->chan_lock);
                return 0;
        }
 
+       l2cap_chan_lock(chan);
+
        l2cap_chan_del(chan, 0);
-       bh_unlock_sock(sk);
+
+       l2cap_chan_unlock(chan);
 
        chan->ops->close(chan->data);
+
+       mutex_unlock(&conn->chan_lock);
+
        return 0;
 }
 
@@ -3074,7 +3200,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
                        conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
                return 0;
 
-       del_timer(&conn->info_timer);
+       cancel_delayed_work(&conn->info_timer);
 
        if (result != L2CAP_IR_SUCCESS) {
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
@@ -3085,7 +3211,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
                return 0;
        }
 
-       if (type == L2CAP_IT_FEAT_MASK) {
+       switch (type) {
+       case L2CAP_IT_FEAT_MASK:
                conn->feat_mask = get_unaligned_le32(rsp->data);
 
                if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
@@ -3102,11 +3229,15 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 
                        l2cap_conn_start(conn);
                }
-       } else if (type == L2CAP_IT_FIXED_CHAN) {
+               break;
+
+       case L2CAP_IT_FIXED_CHAN:
+               conn->fixed_chan_mask = rsp->data[0];
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
                conn->info_ident = 0;
 
                l2cap_conn_start(conn);
+               break;
        }
 
        return 0;
@@ -3538,14 +3669,10 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
        bt_cb(skb)->sar = sar;
 
        next_skb = skb_peek(&chan->srej_q);
-       if (!next_skb) {
-               __skb_queue_tail(&chan->srej_q, skb);
-               return 0;
-       }
 
        tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
 
-       do {
+       while (next_skb) {
                if (bt_cb(next_skb)->tx_seq == tx_seq)
                        return -EINVAL;
 
@@ -3558,9 +3685,10 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
                }
 
                if (skb_queue_is_last(&chan->srej_q, next_skb))
-                       break;
-
-       } while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
+                       next_skb = NULL;
+               else
+                       next_skb = skb_queue_next(&chan->srej_q, next_skb);
+       }
 
        __skb_queue_tail(&chan->srej_q, skb);
 
@@ -3669,19 +3797,11 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3
 
 static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
 {
-       u32 control;
-
        BT_DBG("chan %p, Enter local busy", chan);
 
        set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 
-       control = __set_reqseq(chan, chan->buffer_seq);
-       control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
-       l2cap_send_sframe(chan, control);
-
-       set_bit(CONN_RNR_SENT, &chan->conn_state);
-
-       __clear_ack_timer(chan);
+       __set_ack_timer(chan);
 }
 
 static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
@@ -3764,7 +3884,7 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
        }
 }
 
-static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
+static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
 {
        struct srej_list *new;
        u32 control;
@@ -3775,6 +3895,9 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
                l2cap_send_sframe(chan, control);
 
                new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
+               if (!new)
+                       return -ENOMEM;
+
                new->tx_seq = chan->expected_tx_seq;
 
                chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
@@ -3783,6 +3906,8 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
        }
 
        chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
+
+       return 0;
 }
 
 static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
@@ -3816,8 +3941,11 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
                goto drop;
        }
 
-       if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
+       if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
+               if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
+                       l2cap_send_ack(chan);
                goto drop;
+       }
 
        if (tx_seq == chan->expected_tx_seq)
                goto expected;
@@ -3853,7 +3981,12 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
                                        return 0;
                                }
                        }
-                       l2cap_send_srejframe(chan, tx_seq);
+
+                       err = l2cap_send_srejframe(chan, tx_seq);
+                       if (err < 0) {
+                               l2cap_send_disconn_req(chan->conn, chan, -err);
+                               return err;
+                       }
                }
        } else {
                expected_tx_seq_offset = __seq_offset(chan,
@@ -3873,11 +4006,15 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
                __skb_queue_head_init(&chan->srej_q);
                l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
 
-               set_bit(CONN_SEND_PBIT, &chan->conn_state);
-
-               l2cap_send_srejframe(chan, tx_seq);
+               /* Set P-bit only if there are some I-frames to ack. */
+               if (__clear_ack_timer(chan))
+                       set_bit(CONN_SEND_PBIT, &chan->conn_state);
 
-               __clear_ack_timer(chan);
+               err = l2cap_send_srejframe(chan, tx_seq);
+               if (err < 0) {
+                       l2cap_send_disconn_req(chan->conn, chan, -err);
+                       return err;
+               }
        }
        return 0;
 
@@ -3904,11 +4041,12 @@ expected:
                        l2cap_retransmit_frames(chan);
        }
 
-       __set_ack_timer(chan);
 
        chan->num_acked = (chan->num_acked + 1) % num_to_ack;
        if (chan->num_acked == num_to_ack - 1)
                l2cap_send_ack(chan);
+       else
+               __set_ack_timer(chan);
 
        return 0;
 
@@ -4076,9 +4214,8 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_cont
        return 0;
 }
 
-static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
+static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
 {
-       struct l2cap_chan *chan = l2cap_pi(sk)->chan;
        u32 control;
        u16 req_seq;
        int len, next_tx_seq_offset, req_seq_offset;
@@ -4146,7 +4283,6 @@ drop:
 static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
 {
        struct l2cap_chan *chan;
-       struct sock *sk = NULL;
        u32 control;
        u16 tx_seq;
        int len;
@@ -4154,10 +4290,12 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
        chan = l2cap_get_chan_by_scid(conn, cid);
        if (!chan) {
                BT_DBG("unknown cid 0x%4.4x", cid);
-               goto drop;
+               /* Drop packet and return */
+               kfree_skb(skb);
+               return 0;
        }
 
-       sk = chan->sk;
+       l2cap_chan_lock(chan);
 
        BT_DBG("chan %p, len %d", chan, skb->len);
 
@@ -4179,12 +4317,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                break;
 
        case L2CAP_MODE_ERTM:
-               if (!sock_owned_by_user(sk)) {
-                       l2cap_ertm_data_rcv(sk, skb);
-               } else {
-                       if (sk_add_backlog(sk, skb))
-                               goto drop;
-               }
+               l2cap_ertm_data_rcv(chan, skb);
 
                goto done;
 
@@ -4233,26 +4366,20 @@ drop:
        kfree_skb(skb);
 
 done:
-       if (sk)
-               bh_unlock_sock(sk);
+       l2cap_chan_unlock(chan);
 
        return 0;
 }
 
 static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
 {
-       struct sock *sk = NULL;
        struct l2cap_chan *chan;
 
        chan = l2cap_global_chan_by_psm(0, psm, conn->src);
        if (!chan)
                goto drop;
 
-       sk = chan->sk;
-
-       bh_lock_sock(sk);
-
-       BT_DBG("sk %p, len %d", sk, skb->len);
+       BT_DBG("chan %p, len %d", chan, skb->len);
 
        if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
                goto drop;
@@ -4261,31 +4388,23 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
                goto drop;
 
        if (!chan->ops->recv(chan->data, skb))
-               goto done;
+               return 0;
 
 drop:
        kfree_skb(skb);
 
-done:
-       if (sk)
-               bh_unlock_sock(sk);
        return 0;
 }
 
 static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
 {
-       struct sock *sk = NULL;
        struct l2cap_chan *chan;
 
        chan = l2cap_global_chan_by_scid(0, cid, conn->src);
        if (!chan)
                goto drop;
 
-       sk = chan->sk;
-
-       bh_lock_sock(sk);
-
-       BT_DBG("sk %p, len %d", sk, skb->len);
+       BT_DBG("chan %p, len %d", chan, skb->len);
 
        if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
                goto drop;
@@ -4294,14 +4413,11 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct
                goto drop;
 
        if (!chan->ops->recv(chan->data, skb))
-               goto done;
+               return 0;
 
 drop:
        kfree_skb(skb);
 
-done:
-       if (sk)
-               bh_unlock_sock(sk);
        return 0;
 }
 
@@ -4351,14 +4467,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 
 /* ---- L2CAP interface with lower layer (HCI) ---- */
 
-static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
+int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        int exact = 0, lm1 = 0, lm2 = 0;
        struct l2cap_chan *c;
 
-       if (type != ACL_LINK)
-               return -EINVAL;
-
        BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
 
        /* Find listening sockets and check their link_mode */
@@ -4385,15 +4498,12 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
        return exact ? lm1 : lm2;
 }
 
-static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
+int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
 {
        struct l2cap_conn *conn;
 
        BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
 
-       if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
-               return -EINVAL;
-
        if (!status) {
                conn = l2cap_conn_add(hcon, status);
                if (conn)
@@ -4404,27 +4514,22 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
        return 0;
 }
 
-static int l2cap_disconn_ind(struct hci_conn *hcon)
+int l2cap_disconn_ind(struct hci_conn *hcon)
 {
        struct l2cap_conn *conn = hcon->l2cap_data;
 
        BT_DBG("hcon %p", hcon);
 
-       if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
+       if (!conn)
                return HCI_ERROR_REMOTE_USER_TERM;
-
        return conn->disc_reason;
 }
 
-static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
+int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
 {
        BT_DBG("hcon %p reason %d", hcon, reason);
 
-       if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
-               return -EINVAL;
-
        l2cap_conn_del(hcon, bt_to_errno(reason));
-
        return 0;
 }
 
@@ -4436,7 +4541,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
        if (encrypt == 0x00) {
                if (chan->sec_level == BT_SECURITY_MEDIUM) {
                        __clear_chan_timer(chan);
-                       __set_chan_timer(chan, HZ * 5);
+                       __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
                } else if (chan->sec_level == BT_SECURITY_HIGH)
                        l2cap_chan_close(chan, ECONNREFUSED);
        } else {
@@ -4445,7 +4550,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
        }
 }
 
-static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
+int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 {
        struct l2cap_conn *conn = hcon->l2cap_data;
        struct l2cap_chan *chan;
@@ -4457,59 +4562,57 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 
        if (hcon->type == LE_LINK) {
                smp_distribute_keys(conn, 0);
-               del_timer(&conn->security_timer);
+               cancel_delayed_work(&conn->security_timer);
        }
 
-       read_lock(&conn->chan_lock);
+       mutex_lock(&conn->chan_lock);
 
        list_for_each_entry(chan, &conn->chan_l, list) {
-               struct sock *sk = chan->sk;
-
-               bh_lock_sock(sk);
+               l2cap_chan_lock(chan);
 
                BT_DBG("chan->scid %d", chan->scid);
 
                if (chan->scid == L2CAP_CID_LE_DATA) {
                        if (!status && encrypt) {
                                chan->sec_level = hcon->sec_level;
-                               l2cap_chan_ready(sk);
+                               l2cap_chan_ready(chan);
                        }
 
-                       bh_unlock_sock(sk);
+                       l2cap_chan_unlock(chan);
                        continue;
                }
 
                if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
-                       bh_unlock_sock(sk);
+                       l2cap_chan_unlock(chan);
                        continue;
                }
 
                if (!status && (chan->state == BT_CONNECTED ||
                                                chan->state == BT_CONFIG)) {
+                       struct sock *sk = chan->sk;
+
+                       bt_sk(sk)->suspended = false;
+                       sk->sk_state_change(sk);
+
                        l2cap_check_encryption(chan, encrypt);
-                       bh_unlock_sock(sk);
+                       l2cap_chan_unlock(chan);
                        continue;
                }
 
                if (chan->state == BT_CONNECT) {
                        if (!status) {
-                               struct l2cap_conn_req req;
-                               req.scid = cpu_to_le16(chan->scid);
-                               req.psm  = chan->psm;
-
-                               chan->ident = l2cap_get_ident(conn);
-                               set_bit(CONF_CONNECT_PEND, &chan->conf_state);
-
-                               l2cap_send_cmd(conn, chan->ident,
-                                       L2CAP_CONN_REQ, sizeof(req), &req);
+                               l2cap_send_conn_req(chan);
                        } else {
                                __clear_chan_timer(chan);
-                               __set_chan_timer(chan, HZ / 10);
+                               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                        }
                } else if (chan->state == BT_CONNECT2) {
+                       struct sock *sk = chan->sk;
                        struct l2cap_conn_rsp rsp;
                        __u16 res, stat;
 
+                       lock_sock(sk);
+
                        if (!status) {
                                if (bt_sk(sk)->defer_setup) {
                                        struct sock *parent = bt_sk(sk)->parent;
@@ -4518,17 +4621,19 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                                        if (parent)
                                                parent->sk_data_ready(parent, 0);
                                } else {
-                                       l2cap_state_change(chan, BT_CONFIG);
+                                       __l2cap_state_change(chan, BT_CONFIG);
                                        res = L2CAP_CR_SUCCESS;
                                        stat = L2CAP_CS_NO_INFO;
                                }
                        } else {
-                               l2cap_state_change(chan, BT_DISCONN);
-                               __set_chan_timer(chan, HZ / 10);
+                               __l2cap_state_change(chan, BT_DISCONN);
+                               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                                res = L2CAP_CR_SEC_BLOCK;
                                stat = L2CAP_CS_NO_INFO;
                        }
 
+                       release_sock(sk);
+
                        rsp.scid   = cpu_to_le16(chan->dcid);
                        rsp.dcid   = cpu_to_le16(chan->scid);
                        rsp.result = cpu_to_le16(res);
@@ -4537,15 +4642,15 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                                                        sizeof(rsp), &rsp);
                }
 
-               bh_unlock_sock(sk);
+               l2cap_chan_unlock(chan);
        }
 
-       read_unlock(&conn->chan_lock);
+       mutex_unlock(&conn->chan_lock);
 
        return 0;
 }
 
-static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
+int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
 {
        struct l2cap_conn *conn = hcon->l2cap_data;
 
@@ -4601,16 +4706,17 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
 
                if (chan && chan->sk) {
                        struct sock *sk = chan->sk;
+                       lock_sock(sk);
 
                        if (chan->imtu < len - L2CAP_HDR_SIZE) {
                                BT_ERR("Frame exceeding recv MTU (len %d, "
                                                        "MTU %d)", len,
                                                        chan->imtu);
-                               bh_unlock_sock(sk);
+                               release_sock(sk);
                                l2cap_conn_unreliable(conn, ECOMM);
                                goto drop;
                        }
-                       bh_unlock_sock(sk);
+                       release_sock(sk);
                }
 
                /* Allocate skb for the complete frame (with header) */
@@ -4660,7 +4766,7 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
 {
        struct l2cap_chan *c;
 
-       read_lock_bh(&chan_list_lock);
+       read_lock(&chan_list_lock);
 
        list_for_each_entry(c, &chan_list, global_l) {
                struct sock *sk = c->sk;
@@ -4671,9 +4777,9 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
                                        c->state, __le16_to_cpu(c->psm),
                                        c->scid, c->dcid, c->imtu, c->omtu,
                                        c->sec_level, c->mode);
-}
+       }
 
-       read_unlock_bh(&chan_list_lock);
+       read_unlock(&chan_list_lock);
 
        return 0;
 }
@@ -4692,17 +4798,6 @@ static const struct file_operations l2cap_debugfs_fops = {
 
 static struct dentry *l2cap_debugfs;
 
-static struct hci_proto l2cap_hci_proto = {
-       .name           = "L2CAP",
-       .id             = HCI_PROTO_L2CAP,
-       .connect_ind    = l2cap_connect_ind,
-       .connect_cfm    = l2cap_connect_cfm,
-       .disconn_ind    = l2cap_disconn_ind,
-       .disconn_cfm    = l2cap_disconn_cfm,
-       .security_cfm   = l2cap_security_cfm,
-       .recv_acldata   = l2cap_recv_acldata
-};
-
 int __init l2cap_init(void)
 {
        int err;
@@ -4711,13 +4806,6 @@ int __init l2cap_init(void)
        if (err < 0)
                return err;
 
-       err = hci_register_proto(&l2cap_hci_proto);
-       if (err < 0) {
-               BT_ERR("L2CAP protocol registration failed");
-               bt_sock_unregister(BTPROTO_L2CAP);
-               goto error;
-       }
-
        if (bt_debugfs) {
                l2cap_debugfs = debugfs_create_file("l2cap", 0444,
                                        bt_debugfs, NULL, &l2cap_debugfs_fops);
@@ -4726,24 +4814,13 @@ int __init l2cap_init(void)
        }
 
        return 0;
-
-error:
-       l2cap_cleanup_sockets();
-       return err;
 }
 
 void l2cap_exit(void)
 {
        debugfs_remove(l2cap_debugfs);
-
-       if (hci_unregister_proto(&l2cap_hci_proto) < 0)
-               BT_ERR("L2CAP protocol unregistration failed");
-
        l2cap_cleanup_sockets();
 }
 
 module_param(disable_ertm, bool, 0644);
 MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
-
-module_param(enable_hs, bool, 0644);
-MODULE_PARM_DESC(enable_hs, "Enable High Speed");