Bluetooth: notify userspace of security level change
[linux-flexiantxendom0-3.2.10.git] / net / bluetooth / l2cap_core.c
index 4638dbb..6f9c25b 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/crc16.h>
 #include <net/sock.h>
 
-#include <asm/system.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -217,18 +216,33 @@ static void l2cap_state_change(struct l2cap_chan *chan, int state)
        release_sock(sk);
 }
 
+static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err)
+{
+       struct sock *sk = chan->sk;
+
+       sk->sk_err = err;
+}
+
+static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
+{
+       struct sock *sk = chan->sk;
+
+       lock_sock(sk);
+       __l2cap_chan_set_err(chan, err);
+       release_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;
-       struct sock *sk = chan->sk;
        int reason;
 
        BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
 
        mutex_lock(&conn->chan_lock);
-       lock_sock(sk);
+       l2cap_chan_lock(chan);
 
        if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
                reason = ECONNREFUSED;
@@ -240,7 +254,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
 
        l2cap_chan_close(chan, reason);
 
-       release_sock(sk);
+       l2cap_chan_unlock(chan);
 
        chan->ops->close(chan->data);
        mutex_unlock(&conn->chan_lock);
@@ -284,7 +298,7 @@ void l2cap_chan_destroy(struct l2cap_chan *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);
@@ -330,13 +344,16 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 
        l2cap_chan_hold(chan);
 
-       mutex_lock(&conn->chan_lock);
        list_add(&chan->list, &conn->chan_l);
+}
+
+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);
 }
 
-/* Delete channel.
- * Must be called on the locked socket. */
 static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 {
        struct sock *sk = chan->sk;
@@ -357,11 +374,13 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
                hci_conn_put(conn->hcon);
        }
 
+       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);
@@ -369,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;
@@ -401,10 +422,10 @@ static void l2cap_chan_cleanup_listen(struct sock *parent)
        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);
        }
@@ -420,10 +441,12 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
 
        switch (chan->state) {
        case BT_LISTEN:
+               lock_sock(sk);
                l2cap_chan_cleanup_listen(sk);
 
                __l2cap_state_change(chan, BT_CLOSED);
                sock_set_flag(sk, SOCK_ZAPPED);
+               release_sock(sk);
                break;
 
        case BT_CONNECTED:
@@ -466,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;
        }
 }
@@ -641,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;
@@ -650,17 +690,8 @@ static void l2cap_do_start(struct l2cap_chan *chan)
                        return;
 
                if (l2cap_chan_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);
-               }
+                               __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);
@@ -668,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);
 
-               schedule_delayed_work(&conn->info_timer,
-                                       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);
@@ -694,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);
@@ -713,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);
 
+       lock_sock(sk);
        __l2cap_state_change(chan, BT_DISCONN);
-       sk->sk_err = err;
+       __l2cap_chan_set_err(chan, err);
+       release_sock(sk);
 }
 
 /* ---- L2CAP connections ---- */
@@ -729,40 +759,29 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
        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_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 */
                                l2cap_chan_close(chan, ECONNRESET);
-                               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;
@@ -771,6 +790,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                        rsp.dcid = cpu_to_le16(chan->scid);
 
                        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);
@@ -783,6 +803,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                                        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);
@@ -793,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;
                        }
 
@@ -803,7 +824,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                        chan->num_conf_req++;
                }
 
-               bh_unlock_sock(sk);
+               l2cap_chan_unlock(chan);
        }
 
        mutex_unlock(&conn->chan_lock);
@@ -892,7 +913,11 @@ clean:
 static void l2cap_chan_ready(struct l2cap_chan *chan)
 {
        struct sock *sk = chan->sk;
-       struct sock *parent = bt_sk(sk)->parent;
+       struct sock *parent;
+
+       lock_sock(sk);
+
+       parent = bt_sk(sk)->parent;
 
        BT_DBG("sk %p, parent %p", sk, parent);
 
@@ -904,6 +929,8 @@ static void l2cap_chan_ready(struct l2cap_chan *chan)
 
        if (parent)
                parent->sk_data_ready(parent, 0);
+
+       release_sock(sk);
 }
 
 static void l2cap_conn_ready(struct l2cap_conn *conn)
@@ -921,23 +948,25 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
        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(chan);
 
                } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
+                       struct sock *sk = chan->sk;
                        __clear_chan_timer(chan);
+                       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);
        }
 
        mutex_unlock(&conn->chan_lock);
@@ -953,10 +982,8 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
        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);
        }
 
        mutex_unlock(&conn->chan_lock);
@@ -977,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;
@@ -990,10 +1016,12 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 
        /* Kill channels */
        list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
-               sk = chan->sk;
-               lock_sock(sk);
+               l2cap_chan_lock(chan);
+
                l2cap_chan_del(chan, err);
-               release_sock(sk);
+
+               l2cap_chan_unlock(chan);
+
                chan->ops->close(chan->data);
        }
 
@@ -1124,7 +1152,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
 
        hci_dev_lock(hdev);
 
-       lock_sock(sk);
+       l2cap_chan_lock(chan);
 
        /* PSM must be odd and lsb of upper byte must be 0 */
        if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
@@ -1151,17 +1179,21 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
                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:
@@ -1171,11 +1203,15 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
 
        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;
 
@@ -1203,16 +1239,18 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
        /* 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);
+       l2cap_state_change(chan, BT_CONNECT);
        __set_chan_timer(chan, sk->sk_sndtimeo);
 
        if (hcon->state == BT_CONNECTED) {
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
                        __clear_chan_timer(chan);
                        if (l2cap_chan_check_security(chan))
-                               __l2cap_state_change(chan, BT_CONNECTED);
+                               l2cap_state_change(chan, BT_CONNECTED);
                } else
                        l2cap_do_start(chan);
        }
@@ -1220,6 +1258,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
        err = 0;
 
 done:
+       l2cap_chan_unlock(chan);
        hci_dev_unlock(hdev);
        hci_dev_put(hdev);
        return err;
@@ -1261,14 +1300,15 @@ static void l2cap_monitor_timeout(struct work_struct *work)
 {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
                                                        monitor_timer.work);
-       struct sock *sk = chan->sk;
 
        BT_DBG("chan %p", chan);
 
-       lock_sock(sk);
+       l2cap_chan_lock(chan);
+
        if (chan->retry_count >= chan->remote_max_tx) {
                l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
-               release_sock(sk);
+               l2cap_chan_unlock(chan);
+               l2cap_chan_put(chan);
                return;
        }
 
@@ -1276,25 +1316,28 @@ static void l2cap_monitor_timeout(struct work_struct *work)
        __set_monitor_timer(chan);
 
        l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
-       release_sock(sk);
+       l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 }
 
 static void l2cap_retrans_timeout(struct work_struct *work)
 {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
                                                        retrans_timer.work);
-       struct sock *sk = chan->sk;
 
        BT_DBG("chan %p", chan);
 
-       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);
-       release_sock(sk);
+
+       l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 }
 
 static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
@@ -1505,7 +1548,9 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan)
        l2cap_send_sframe(chan, control);
 }
 
-static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, 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 = chan->conn;
        struct sk_buff **frag;
@@ -1523,7 +1568,8 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr
                count = min_t(unsigned int, conn->mtu, len);
 
                *frag = chan->ops->alloc_skb(chan, count,
-                                       msg->msg_flags & MSG_DONTWAIT, &err);
+                                            msg->msg_flags & MSG_DONTWAIT,
+                                            &err);
 
                if (!*frag)
                        return err;
@@ -1555,7 +1601,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
        count = min_t(unsigned int, (conn->mtu - hlen), len);
 
        skb = chan->ops->alloc_skb(chan, count + hlen,
-                                       msg->msg_flags & MSG_DONTWAIT, &err);
+                                  msg->msg_flags & MSG_DONTWAIT, &err);
 
        if (!skb)
                return ERR_PTR(err);
@@ -1590,7 +1636,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
        count = min_t(unsigned int, (conn->mtu - hlen), len);
 
        skb = chan->ops->alloc_skb(chan, count + hlen,
-                                       msg->msg_flags & MSG_DONTWAIT, &err);
+                                  msg->msg_flags & MSG_DONTWAIT, &err);
 
        if (!skb)
                return ERR_PTR(err);
@@ -1985,9 +2031,11 @@ static void l2cap_ack_timeout(struct work_struct *work)
 
        BT_DBG("chan %p", chan);
 
-       lock_sock(chan->sk);
+       l2cap_chan_lock(chan);
+
        __l2cap_send_ack(chan);
-       release_sock(chan->sk);
+
+       l2cap_chan_unlock(chan);
 
        l2cap_chan_put(chan);
 }
@@ -2648,7 +2696,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        bt_accept_enqueue(parent, sk);
 
-       l2cap_chan_add(conn, chan);
+       __l2cap_chan_add(conn, chan);
 
        dcid = chan->scid;
 
@@ -2697,8 +2745,7 @@ sendresp:
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
                conn->info_ident = l2cap_get_ident(conn);
 
-               schedule_delayed_work(&conn->info_timer,
-                                       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);
@@ -2721,7 +2768,6 @@ 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;
 
@@ -2751,8 +2797,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        err = 0;
 
-       sk = chan->sk;
-       lock_sock(sk);
+       l2cap_chan_lock(chan);
 
        switch (result) {
        case L2CAP_CR_SUCCESS:
@@ -2778,7 +2823,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
                break;
        }
 
-       release_sock(sk);
+       l2cap_chan_unlock(chan);
 
 unlock:
        mutex_unlock(&conn->chan_lock);
@@ -2803,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);
@@ -2815,8 +2859,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (!chan)
                return -ENOENT;
 
-       sk = chan->sk;
-       lock_sock(sk);
+       l2cap_chan_lock(chan);
 
        if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
                struct l2cap_cmd_rej_cid rej;
@@ -2905,7 +2948,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        }
 
 unlock:
-       release_sock(sk);
+       l2cap_chan_unlock(chan);
        return 0;
 }
 
@@ -2914,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);
@@ -2928,8 +2970,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (!chan)
                return 0;
 
-       sk = chan->sk;
-       lock_sock(sk);
+       l2cap_chan_lock(chan);
 
        switch (result) {
        case L2CAP_CONF_SUCCESS:
@@ -2988,9 +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,
-                               msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT));
+               l2cap_chan_set_err(chan, ECONNRESET);
+
+               __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
                l2cap_send_disconn_req(conn, chan, ECONNRESET);
                goto done;
        }
@@ -3014,7 +3055,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        }
 
 done:
-       release_sock(sk);
+       l2cap_chan_unlock(chan);
        return 0;
 }
 
@@ -3039,17 +3080,21 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
                return 0;
        }
 
+       l2cap_chan_lock(chan);
+
        sk = chan->sk;
-       lock_sock(sk);
 
        rsp.dcid = cpu_to_le16(chan->scid);
        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;
+       release_sock(sk);
 
        l2cap_chan_del(chan, ECONNRESET);
-       release_sock(sk);
+
+       l2cap_chan_unlock(chan);
 
        chan->ops->close(chan->data);
 
@@ -3063,7 +3108,6 @@ 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);
@@ -3078,11 +3122,11 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
                return 0;
        }
 
-       sk = chan->sk;
-       lock_sock(sk);
+       l2cap_chan_lock(chan);
 
        l2cap_chan_del(chan, 0);
-       release_sock(sk);
+
+       l2cap_chan_unlock(chan);
 
        chan->ops->close(chan->data);
 
@@ -3167,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) {
@@ -3184,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;
@@ -4234,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;
@@ -4242,11 +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;
-       lock_sock(sk);
+       l2cap_chan_lock(chan);
 
        BT_DBG("chan %p, len %d", chan, skb->len);
 
@@ -4317,26 +4366,20 @@ drop:
        kfree_skb(skb);
 
 done:
-       if (sk)
-               release_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;
-
-       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;
@@ -4345,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)
-               release_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;
-
-       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;
@@ -4378,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)
-               release_sock(sk);
        return 0;
 }
 
@@ -4509,8 +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,
-                                       msecs_to_jiffies(L2CAP_ENC_TIMEOUT));
+                       __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
                } else if (chan->sec_level == BT_SECURITY_HIGH)
                        l2cap_chan_close(chan, ECONNREFUSED);
        } else {
@@ -4537,9 +4568,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
        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);
 
@@ -4549,42 +4578,41 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                                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,
-                                       msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
+                               __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;
@@ -4599,12 +4627,13 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                                }
                        } else {
                                __l2cap_state_change(chan, BT_DISCONN);
-                               __set_chan_timer(chan,
-                                       msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
+                               __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);
@@ -4613,7 +4642,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                                                        sizeof(rsp), &rsp);
                }
 
-               bh_unlock_sock(sk);
+               l2cap_chan_unlock(chan);
        }
 
        mutex_unlock(&conn->chan_lock);