]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/bluetooth/l2cap_core.c
Merge remote-tracking branch 'wireless-next/master'
[karo-tx-linux.git] / net / bluetooth / l2cap_core.c
index 63fa11109a1c391725d5efec2075c1524d9f1a1a..0c3446da1ec9d7f6765c7f4523ad08c6bd20dbe3 100644 (file)
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
-#include <net/bluetooth/smp.h>
-#include <net/bluetooth/a2mp.h>
-#include <net/bluetooth/amp.h>
+
+#include "smp.h"
+#include "a2mp.h"
+#include "amp.h"
 
 bool disable_ertm;
 
-static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
-static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
+static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD;
+static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP | L2CAP_FC_CONNLESS, };
 
 static LIST_HEAD(chan_list);
 static DEFINE_RWLOCK(chan_list_lock);
@@ -58,6 +59,18 @@ static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err);
 static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
                     struct sk_buff_head *skbs, u8 event);
 
+static inline __u8 bdaddr_type(struct hci_conn *hcon, __u8 type)
+{
+       if (hcon->type == LE_LINK) {
+               if (type == ADDR_LE_DEV_PUBLIC)
+                       return BDADDR_LE_PUBLIC;
+               else
+                       return BDADDR_LE_RANDOM;
+       }
+
+       return BDADDR_BREDR;
+}
+
 /* ---- L2CAP channels ---- */
 
 static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
@@ -148,7 +161,7 @@ static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
        struct l2cap_chan *c;
 
        list_for_each_entry(c, &chan_list, global_l) {
-               if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
+               if (c->sport == psm && !bacmp(&c->src, src))
                        return c;
        }
        return NULL;
@@ -620,10 +633,8 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
 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 %s sk %p", chan, state_to_string(chan->state),
-              sk);
+       BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
 
        switch (chan->state) {
        case BT_LISTEN:
@@ -634,6 +645,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
        case BT_CONFIG:
                if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
                    conn->hcon->type == ACL_LINK) {
+                       struct sock *sk = chan->sk;
                        __set_chan_timer(chan, sk->sk_sndtimeo);
                        l2cap_send_disconn_req(chan, reason);
                } else
@@ -646,10 +658,11 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
                        struct l2cap_conn_rsp rsp;
                        __u16 result;
 
-                       if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))
+                       if (test_bit(FLAG_DEFER_SETUP, &chan->flags))
                                result = L2CAP_CR_SEC_BLOCK;
                        else
                                result = L2CAP_CR_BAD_PSM;
+
                        l2cap_state_change(chan, BT_DISCONN);
 
                        rsp.scid   = cpu_to_le16(chan->dcid);
@@ -676,7 +689,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
 
 static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
 {
-       if (chan->chan_type == L2CAP_CHAN_RAW) {
+       switch (chan->chan_type) {
+       case L2CAP_CHAN_RAW:
                switch (chan->sec_level) {
                case BT_SECURITY_HIGH:
                        return HCI_AT_DEDICATED_BONDING_MITM;
@@ -685,15 +699,29 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
                default:
                        return HCI_AT_NO_BONDING;
                }
-       } else if (chan->psm == __constant_cpu_to_le16(L2CAP_PSM_SDP)) {
-               if (chan->sec_level == BT_SECURITY_LOW)
-                       chan->sec_level = BT_SECURITY_SDP;
-
+               break;
+       case L2CAP_CHAN_CONN_LESS:
+               if (chan->psm == __constant_cpu_to_le16(L2CAP_PSM_3DSP)) {
+                       if (chan->sec_level == BT_SECURITY_LOW)
+                               chan->sec_level = BT_SECURITY_SDP;
+               }
                if (chan->sec_level == BT_SECURITY_HIGH)
                        return HCI_AT_NO_BONDING_MITM;
                else
                        return HCI_AT_NO_BONDING;
-       } else {
+               break;
+       case L2CAP_CHAN_CONN_ORIENTED:
+               if (chan->psm == __constant_cpu_to_le16(L2CAP_PSM_SDP)) {
+                       if (chan->sec_level == BT_SECURITY_LOW)
+                               chan->sec_level = BT_SECURITY_SDP;
+
+                       if (chan->sec_level == BT_SECURITY_HIGH)
+                               return HCI_AT_NO_BONDING_MITM;
+                       else
+                               return HCI_AT_NO_BONDING;
+               }
+               /* fall through */
+       default:
                switch (chan->sec_level) {
                case BT_SECURITY_HIGH:
                        return HCI_AT_GENERAL_BONDING_MITM;
@@ -702,6 +730,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
                default:
                        return HCI_AT_NO_BONDING;
                }
+               break;
        }
 }
 
@@ -1015,14 +1044,29 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
 static bool __amp_capable(struct l2cap_chan *chan)
 {
        struct l2cap_conn *conn = chan->conn;
+       struct hci_dev *hdev;
+       bool amp_available = false;
 
-       if (enable_hs &&
-           hci_amp_capable() &&
-           chan->chan_policy == BT_CHANNEL_POLICY_AMP_PREFERRED &&
-           conn->fixed_chan_mask & L2CAP_FC_A2MP)
-               return true;
-       else
+       if (!conn->hs_enabled)
+               return false;
+
+       if (!(conn->fixed_chan_mask & L2CAP_FC_A2MP))
                return false;
+
+       read_lock(&hci_dev_list_lock);
+       list_for_each_entry(hdev, &hci_dev_list, list) {
+               if (hdev->amp_type != AMP_TYPE_BREDR &&
+                   test_bit(HCI_UP, &hdev->flags)) {
+                       amp_available = true;
+                       break;
+               }
+       }
+       read_unlock(&hci_dev_list_lock);
+
+       if (chan->chan_policy == BT_CHANNEL_POLICY_AMP_PREFERRED)
+               return amp_available;
+
+       return false;
 }
 
 static bool l2cap_check_efs(struct l2cap_chan *chan)
@@ -1225,8 +1269,6 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
        mutex_lock(&conn->chan_lock);
 
        list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
-               struct sock *sk = chan->sk;
-
                l2cap_chan_lock(chan);
 
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
@@ -1258,9 +1300,10 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                        rsp.dcid = cpu_to_le16(chan->scid);
 
                        if (l2cap_chan_check_security(chan)) {
+                               struct sock *sk = chan->sk;
+
                                lock_sock(sk);
-                               if (test_bit(BT_SK_DEFER_SETUP,
-                                            &bt_sk(sk)->flags)) {
+                               if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
                                        rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND);
                                        rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
                                        chan->ops->defer(chan);
@@ -1309,8 +1352,6 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
        read_lock(&chan_list_lock);
 
        list_for_each_entry(c, &chan_list, global_l) {
-               struct sock *sk = c->sk;
-
                if (state && c->state != state)
                        continue;
 
@@ -1319,16 +1360,16 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
                        int src_any, dst_any;
 
                        /* Exact match. */
-                       src_match = !bacmp(&bt_sk(sk)->src, src);
-                       dst_match = !bacmp(&bt_sk(sk)->dst, dst);
+                       src_match = !bacmp(&c->src, src);
+                       dst_match = !bacmp(&c->dst, dst);
                        if (src_match && dst_match) {
                                read_unlock(&chan_list_lock);
                                return c;
                        }
 
                        /* Closest match */
-                       src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY);
-                       dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY);
+                       src_any = !bacmp(&c->src, BDADDR_ANY);
+                       dst_any = !bacmp(&c->dst, BDADDR_ANY);
                        if ((src_match && dst_any) || (src_any && dst_match) ||
                            (src_any && dst_any))
                                c1 = c;
@@ -1349,7 +1390,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
        /* Check if we have socket listening on cid */
        pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT,
-                                         conn->src, conn->dst);
+                                         &conn->hcon->src, &conn->hcon->dst);
        if (!pchan)
                return;
 
@@ -1367,8 +1408,10 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
        chan->dcid = L2CAP_CID_ATT;
 
-       bacpy(&bt_sk(chan->sk)->src, conn->src);
-       bacpy(&bt_sk(chan->sk)->dst, conn->dst);
+       bacpy(&chan->src, &conn->hcon->src);
+       bacpy(&chan->dst, &conn->hcon->dst);
+       chan->src_type = bdaddr_type(conn->hcon, conn->hcon->src_type);
+       chan->dst_type = bdaddr_type(conn->hcon, conn->hcon->dst_type);
 
        __l2cap_chan_add(conn, chan);
 
@@ -1633,11 +1676,12 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
                break;
        }
 
-       conn->src = &hcon->hdev->bdaddr;
-       conn->dst = &hcon->dst;
-
        conn->feat_mask = 0;
 
+       if (hcon->type == ACL_LINK)
+               conn->hs_enabled = test_bit(HCI_HS_ENABLED,
+                                           &hcon->hdev->dev_flags);
+
        spin_lock_init(&conn->lock);
        mutex_init(&conn->chan_lock);
 
@@ -1688,8 +1732,6 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
        read_lock(&chan_list_lock);
 
        list_for_each_entry(c, &chan_list, global_l) {
-               struct sock *sk = c->sk;
-
                if (state && c->state != state)
                        continue;
 
@@ -1698,16 +1740,16 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
                        int src_any, dst_any;
 
                        /* Exact match. */
-                       src_match = !bacmp(&bt_sk(sk)->src, src);
-                       dst_match = !bacmp(&bt_sk(sk)->dst, dst);
+                       src_match = !bacmp(&c->src, src);
+                       dst_match = !bacmp(&c->dst, dst);
                        if (src_match && dst_match) {
                                read_unlock(&chan_list_lock);
                                return c;
                        }
 
                        /* Closest match */
-                       src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY);
-                       dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY);
+                       src_any = !bacmp(&c->src, BDADDR_ANY);
+                       dst_any = !bacmp(&c->dst, BDADDR_ANY);
                        if ((src_match && dst_any) || (src_any && dst_match) ||
                            (src_any && dst_any))
                                c1 = c;
@@ -1723,17 +1765,16 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
                       bdaddr_t *dst, u8 dst_type)
 {
        struct sock *sk = chan->sk;
-       bdaddr_t *src = &bt_sk(sk)->src;
        struct l2cap_conn *conn;
        struct hci_conn *hcon;
        struct hci_dev *hdev;
        __u8 auth_type;
        int err;
 
-       BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", src, dst,
+       BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst,
               dst_type, __le16_to_cpu(psm));
 
-       hdev = hci_get_route(dst, src);
+       hdev = hci_get_route(dst, &chan->src);
        if (!hdev)
                return -EHOSTUNREACH;
 
@@ -1790,9 +1831,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
        }
 
        /* Set destination address and psm */
-       lock_sock(sk);
-       bacpy(&bt_sk(sk)->dst, dst);
-       release_sock(sk);
+       bacpy(&chan->dst, dst);
+       chan->dst_type = dst_type;
 
        chan->psm = psm;
        chan->dcid = cid;
@@ -1825,7 +1865,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
        }
 
        /* Update source addr of the socket */
-       bacpy(src, conn->src);
+       bacpy(&chan->src, &hcon->src);
+       chan->src_type = bdaddr_type(hcon, hcon->src_type);
 
        l2cap_chan_unlock(chan);
        l2cap_chan_add(conn, chan);
@@ -2263,7 +2304,8 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
        int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
        struct l2cap_hdr *lh;
 
-       BT_DBG("chan %p len %zu priority %u", chan, len, priority);
+       BT_DBG("chan %p psm 0x%2.2x len %zu priority %u", chan,
+              __le16_to_cpu(chan->psm), len, priority);
 
        count = min_t(unsigned int, (conn->mtu - hlen), len);
 
@@ -2278,7 +2320,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
        lh->len = cpu_to_le16(len + L2CAP_PSMLEN_SIZE);
-       put_unaligned(chan->psm, skb_put(skb, L2CAP_PSMLEN_SIZE));
+       put_unaligned(chan->psm, (__le16 *) skb_put(skb, L2CAP_PSMLEN_SIZE));
 
        err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
        if (unlikely(err < 0)) {
@@ -3043,8 +3085,8 @@ int l2cap_ertm_init(struct l2cap_chan *chan)
 
        skb_queue_head_init(&chan->tx_q);
 
-       chan->local_amp_id = 0;
-       chan->move_id = 0;
+       chan->local_amp_id = AMP_ID_BREDR;
+       chan->move_id = AMP_ID_BREDR;
        chan->move_state = L2CAP_MOVE_STABLE;
        chan->move_role = L2CAP_MOVE_ROLE_NONE;
 
@@ -3084,20 +3126,20 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
        }
 }
 
-static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
+static inline bool __l2cap_ews_supported(struct l2cap_conn *conn)
 {
-       return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
+       return conn->hs_enabled && conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
 }
 
-static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
+static inline bool __l2cap_efs_supported(struct l2cap_conn *conn)
 {
-       return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
+       return conn->hs_enabled && conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
 }
 
 static void __l2cap_set_ertm_timeouts(struct l2cap_chan *chan,
                                      struct l2cap_conf_rfc *rfc)
 {
-       if (chan->local_amp_id && chan->hs_hcon) {
+       if (chan->local_amp_id != AMP_ID_BREDR && chan->hs_hcon) {
                u64 ertm_to = chan->hs_hcon->hdev->amp_be_flush_to;
 
                /* Class 1 devices have must have ERTM timeouts
@@ -3135,7 +3177,7 @@ static void __l2cap_set_ertm_timeouts(struct l2cap_chan *chan,
 static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
 {
        if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
-           __l2cap_ews_supported(chan)) {
+           __l2cap_ews_supported(chan->conn)) {
                /* use extended control field */
                set_bit(FLAG_EXT_CTRL, &chan->flags);
                chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
@@ -3165,7 +3207,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
                if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
                        break;
 
-               if (__l2cap_efs_supported(chan))
+               if (__l2cap_efs_supported(chan->conn))
                        set_bit(FLAG_EFS_ENABLE, &chan->flags);
 
                /* fall through */
@@ -3317,7 +3359,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
                        break;
 
                case L2CAP_CONF_EWS:
-                       if (!enable_hs)
+                       if (!chan->conn->hs_enabled)
                                return -ECONNREFUSED;
 
                        set_bit(FLAG_EXT_CTRL, &chan->flags);
@@ -3349,7 +3391,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
                }
 
                if (remote_efs) {
-                       if (__l2cap_efs_supported(chan))
+                       if (__l2cap_efs_supported(chan->conn))
                                set_bit(FLAG_EFS_ENABLE, &chan->flags);
                        else
                                return -ECONNREFUSED;
@@ -3724,7 +3766,8 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
        BT_DBG("psm 0x%2.2x scid 0x%4.4x", __le16_to_cpu(psm), scid);
 
        /* Check if we have socket listening on psm */
-       pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src, conn->dst);
+       pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src,
+                                        &conn->hcon->dst);
        if (!pchan) {
                result = L2CAP_CR_BAD_PSM;
                goto sendresp;
@@ -3762,8 +3805,10 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
         */
        conn->hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
 
-       bacpy(&bt_sk(sk)->src, conn->src);
-       bacpy(&bt_sk(sk)->dst, conn->dst);
+       bacpy(&chan->src, &conn->hcon->src);
+       bacpy(&chan->dst, &conn->hcon->dst);
+       chan->src_type = bdaddr_type(conn->hcon, conn->hcon->src_type);
+       chan->dst_type = bdaddr_type(conn->hcon, conn->hcon->dst_type);
        chan->psm  = psm;
        chan->dcid = scid;
        chan->local_amp_id = amp_id;
@@ -3778,7 +3823,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
 
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
                if (l2cap_chan_check_security(chan)) {
-                       if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
+                       if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
                                __l2cap_state_change(chan, BT_CONNECT2);
                                result = L2CAP_CR_PEND;
                                status = L2CAP_CS_AUTHOR_PEND;
@@ -3788,12 +3833,12 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
                                 * The connection will succeed after the
                                 * physical link is up.
                                 */
-                               if (amp_id) {
-                                       __l2cap_state_change(chan, BT_CONNECT2);
-                                       result = L2CAP_CR_PEND;
-                               } else {
+                               if (amp_id == AMP_ID_BREDR) {
                                        __l2cap_state_change(chan, BT_CONFIG);
                                        result = L2CAP_CR_SUCCESS;
+                               } else {
+                                       __l2cap_state_change(chan, BT_CONNECT2);
+                                       result = L2CAP_CR_PEND;
                                }
                                status = L2CAP_CS_NO_INFO;
                        }
@@ -3891,13 +3936,13 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
        if (scid) {
                chan = __l2cap_get_chan_by_scid(conn, scid);
                if (!chan) {
-                       err = -EFAULT;
+                       err = -EBADSLT;
                        goto unlock;
                }
        } else {
                chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
                if (!chan) {
-                       err = -EFAULT;
+                       err = -EBADSLT;
                        goto unlock;
                }
        }
@@ -3985,7 +4030,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
 
        chan = l2cap_get_chan_by_scid(conn, dcid);
        if (!chan)
-               return -ENOENT;
+               return -EBADSLT;
 
        if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
                struct l2cap_cmd_rej_cid rej;
@@ -4213,7 +4258,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
        chan = __l2cap_get_chan_by_scid(conn, dcid);
        if (!chan) {
                mutex_unlock(&conn->chan_lock);
-               return 0;
+               return -EBADSLT;
        }
 
        l2cap_chan_lock(chan);
@@ -4303,7 +4348,7 @@ static inline int l2cap_information_req(struct l2cap_conn *conn,
                if (!disable_ertm)
                        feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
                                | L2CAP_FEAT_FCS;
-               if (enable_hs)
+               if (conn->hs_enabled)
                        feat_mask |= L2CAP_FEAT_EXT_FLOW
                                | L2CAP_FEAT_EXT_WINDOW;
 
@@ -4314,7 +4359,7 @@ static inline int l2cap_information_req(struct l2cap_conn *conn,
                u8 buf[12];
                struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
 
-               if (enable_hs)
+               if (conn->hs_enabled)
                        l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
                else
                        l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
@@ -4411,7 +4456,7 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn,
        if (cmd_len != sizeof(*req))
                return -EPROTO;
 
-       if (!enable_hs)
+       if (!conn->hs_enabled)
                return -EINVAL;
 
        psm = le16_to_cpu(req->psm);
@@ -4420,7 +4465,7 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn,
        BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id);
 
        /* For controller id 0 make BR/EDR connection */
-       if (req->amp_id == HCI_BREDR_ID) {
+       if (req->amp_id == AMP_ID_BREDR) {
                l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP,
                              req->amp_id);
                return 0;
@@ -4442,10 +4487,11 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn,
                struct amp_mgr *mgr = conn->hcon->amp_mgr;
                struct hci_conn *hs_hcon;
 
-               hs_hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, conn->dst);
+               hs_hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK,
+                                                 &conn->hcon->dst);
                if (!hs_hcon) {
                        hci_dev_put(hdev);
-                       return -EFAULT;
+                       return -EBADSLT;
                }
 
                BT_DBG("mgr %p bredr_chan %p hs_hcon %p", mgr, chan, hs_hcon);
@@ -4469,7 +4515,7 @@ error:
        l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
                       sizeof(rsp), &rsp);
 
-       return -EFAULT;
+       return 0;
 }
 
 static void l2cap_send_move_chan_req(struct l2cap_chan *chan, u8 dest_amp_id)
@@ -4655,7 +4701,7 @@ void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
 
        if (chan->state != BT_CONNECTED) {
                /* Ignore logical link if channel is on BR/EDR */
-               if (chan->local_amp_id)
+               if (chan->local_amp_id != AMP_ID_BREDR)
                        l2cap_logical_finish_create(chan, hchan);
        } else {
                l2cap_logical_finish_move(chan, hchan);
@@ -4666,7 +4712,7 @@ void l2cap_move_start(struct l2cap_chan *chan)
 {
        BT_DBG("chan %p", chan);
 
-       if (chan->local_amp_id == HCI_BREDR_ID) {
+       if (chan->local_amp_id == AMP_ID_BREDR) {
                if (chan->chan_policy != BT_CHANNEL_POLICY_AMP_PREFERRED)
                        return;
                chan->move_role = L2CAP_MOVE_ROLE_INITIATOR;
@@ -4838,7 +4884,7 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
 
        BT_DBG("icid 0x%4.4x, dest_amp_id %d", icid, req->dest_amp_id);
 
-       if (!enable_hs)
+       if (!conn->hs_enabled)
                return -EINVAL;
 
        chan = l2cap_get_chan_by_dcid(conn, icid);
@@ -4865,7 +4911,7 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
                goto send_move_response;
        }
 
-       if (req->dest_amp_id) {
+       if (req->dest_amp_id != AMP_ID_BREDR) {
                struct hci_dev *hdev;
                hdev = hci_dev_get(req->dest_amp_id);
                if (!hdev || hdev->dev_type != HCI_AMP ||
@@ -4885,7 +4931,7 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
         */
        if ((__chan_is_moving(chan) ||
             chan->move_role != L2CAP_MOVE_ROLE_NONE) &&
-           bacmp(conn->src, conn->dst) > 0) {
+           bacmp(&conn->hcon->src, &conn->hcon->dst) > 0) {
                result = L2CAP_MR_COLLISION;
                goto send_move_response;
        }
@@ -4895,7 +4941,7 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
        chan->move_id = req->dest_amp_id;
        icid = chan->dcid;
 
-       if (!req->dest_amp_id) {
+       if (req->dest_amp_id == AMP_ID_BREDR) {
                /* Moving to BR/EDR */
                if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
                        chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY;
@@ -5087,7 +5133,7 @@ static int l2cap_move_channel_confirm(struct l2cap_conn *conn,
        if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM) {
                if (result == L2CAP_MC_CONFIRMED) {
                        chan->local_amp_id = chan->move_id;
-                       if (!chan->local_amp_id)
+                       if (chan->local_amp_id == AMP_ID_BREDR)
                                __release_logical_link(chan);
                } else {
                        chan->move_id = chan->local_amp_id;
@@ -5127,7 +5173,7 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
        if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM_RSP) {
                chan->local_amp_id = chan->move_id;
 
-               if (!chan->local_amp_id && chan->hs_hchan)
+               if (chan->local_amp_id == AMP_ID_BREDR && chan->hs_hchan)
                        __release_logical_link(chan);
 
                l2cap_move_done(chan);
@@ -5219,7 +5265,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
 
        case L2CAP_CONN_RSP:
        case L2CAP_CREATE_CHAN_RSP:
-               err = l2cap_connect_create_rsp(conn, cmd, cmd_len, data);
+               l2cap_connect_create_rsp(conn, cmd, cmd_len, data);
                break;
 
        case L2CAP_CONF_REQ:
@@ -5227,7 +5273,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                break;
 
        case L2CAP_CONF_RSP:
-               err = l2cap_config_rsp(conn, cmd, cmd_len, data);
+               l2cap_config_rsp(conn, cmd, cmd_len, data);
                break;
 
        case L2CAP_DISCONN_REQ:
@@ -5235,7 +5281,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                break;
 
        case L2CAP_DISCONN_RSP:
-               err = l2cap_disconnect_rsp(conn, cmd, cmd_len, data);
+               l2cap_disconnect_rsp(conn, cmd, cmd_len, data);
                break;
 
        case L2CAP_ECHO_REQ:
@@ -5250,7 +5296,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                break;
 
        case L2CAP_INFO_RSP:
-               err = l2cap_information_rsp(conn, cmd, cmd_len, data);
+               l2cap_information_rsp(conn, cmd, cmd_len, data);
                break;
 
        case L2CAP_CREATE_CHAN_REQ:
@@ -5262,7 +5308,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                break;
 
        case L2CAP_MOVE_CHAN_RSP:
-               err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
+               l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
                break;
 
        case L2CAP_MOVE_CHAN_CFM:
@@ -5270,7 +5316,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                break;
 
        case L2CAP_MOVE_CHAN_CFM_RSP:
-               err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
+               l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
                break;
 
        default:
@@ -5301,54 +5347,65 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
        }
 }
 
+static __le16 l2cap_err_to_reason(int err)
+{
+       switch (err) {
+       case -EBADSLT:
+               return __constant_cpu_to_le16(L2CAP_REJ_INVALID_CID);
+       case -EMSGSIZE:
+               return __constant_cpu_to_le16(L2CAP_REJ_MTU_EXCEEDED);
+       case -EINVAL:
+       case -EPROTO:
+       default:
+               return __constant_cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
+       }
+}
+
 static inline void l2cap_le_sig_channel(struct l2cap_conn *conn,
                                        struct sk_buff *skb)
 {
-       u8 *data = skb->data;
-       int len = skb->len;
-       struct l2cap_cmd_hdr cmd;
+       struct hci_conn *hcon = conn->hcon;
+       struct l2cap_cmd_hdr *cmd;
+       u16 len;
        int err;
 
-       l2cap_raw_recv(conn, skb);
+       if (hcon->type != LE_LINK)
+               goto drop;
 
-       while (len >= L2CAP_CMD_HDR_SIZE) {
-               u16 cmd_len;
-               memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
-               data += L2CAP_CMD_HDR_SIZE;
-               len  -= L2CAP_CMD_HDR_SIZE;
+       if (skb->len < L2CAP_CMD_HDR_SIZE)
+               goto drop;
 
-               cmd_len = le16_to_cpu(cmd.len);
+       cmd = (void *) skb->data;
+       skb_pull(skb, L2CAP_CMD_HDR_SIZE);
 
-               BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len,
-                      cmd.ident);
+       len = le16_to_cpu(cmd->len);
 
-               if (cmd_len > len || !cmd.ident) {
-                       BT_DBG("corrupted command");
-                       break;
-               }
+       BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd->code, len, cmd->ident);
 
-               err = l2cap_le_sig_cmd(conn, &cmd, data);
-               if (err) {
-                       struct l2cap_cmd_rej_unk rej;
+       if (len != skb->len || !cmd->ident) {
+               BT_DBG("corrupted command");
+               goto drop;
+       }
 
-                       BT_ERR("Wrong link type (%d)", err);
+       err = l2cap_le_sig_cmd(conn, cmd, skb->data);
+       if (err) {
+               struct l2cap_cmd_rej_unk rej;
 
-                       /* FIXME: Map err to a valid reason */
-                       rej.reason = __constant_cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
-                       l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ,
-                                      sizeof(rej), &rej);
-               }
+               BT_ERR("Wrong link type (%d)", err);
 
-               data += cmd_len;
-               len  -= cmd_len;
+               rej.reason = l2cap_err_to_reason(err);
+               l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
+                              sizeof(rej), &rej);
        }
 
+drop:
        kfree_skb(skb);
 }
 
 static inline void l2cap_sig_channel(struct l2cap_conn *conn,
                                     struct sk_buff *skb)
 {
+       struct hci_conn *hcon = conn->hcon;
        u8 *data = skb->data;
        int len = skb->len;
        struct l2cap_cmd_hdr cmd;
@@ -5356,6 +5413,9 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 
        l2cap_raw_recv(conn, skb);
 
+       if (hcon->type != ACL_LINK)
+               goto drop;
+
        while (len >= L2CAP_CMD_HDR_SIZE) {
                u16 cmd_len;
                memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
@@ -5378,8 +5438,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 
                        BT_ERR("Wrong link type (%d)", err);
 
-                       /* FIXME: Map err to a valid reason */
-                       rej.reason = __constant_cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
+                       rej.reason = l2cap_err_to_reason(err);
                        l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ,
                                       sizeof(rej), &rej);
                }
@@ -5388,6 +5447,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
                len  -= cmd_len;
        }
 
+drop:
        kfree_skb(skb);
 }
 
@@ -5784,7 +5844,7 @@ static int l2cap_rx_state_recv(struct l2cap_chan *chan,
                               struct sk_buff *skb, u8 event)
 {
        int err = 0;
-       bool skb_in_use = 0;
+       bool skb_in_use = false;
 
        BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb,
               event);
@@ -5805,7 +5865,7 @@ static int l2cap_rx_state_recv(struct l2cap_chan *chan,
                                                           control->txseq);
 
                        chan->buffer_seq = chan->expected_tx_seq;
-                       skb_in_use = 1;
+                       skb_in_use = true;
 
                        err = l2cap_reassemble_sdu(chan, skb, control);
                        if (err)
@@ -5841,7 +5901,7 @@ static int l2cap_rx_state_recv(struct l2cap_chan *chan,
                         * current frame is stored for later use.
                         */
                        skb_queue_tail(&chan->srej_q, skb);
-                       skb_in_use = 1;
+                       skb_in_use = true;
                        BT_DBG("Queued %p (queue len %d)", skb,
                               skb_queue_len(&chan->srej_q));
 
@@ -5919,7 +5979,7 @@ static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan,
 {
        int err = 0;
        u16 txseq = control->txseq;
-       bool skb_in_use = 0;
+       bool skb_in_use = false;
 
        BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb,
               event);
@@ -5931,7 +5991,7 @@ static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan,
                        /* Keep frame for reassembly later */
                        l2cap_pass_to_tx(chan, control);
                        skb_queue_tail(&chan->srej_q, skb);
-                       skb_in_use = 1;
+                       skb_in_use = true;
                        BT_DBG("Queued %p (queue len %d)", skb,
                               skb_queue_len(&chan->srej_q));
 
@@ -5942,7 +6002,7 @@ static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan,
 
                        l2cap_pass_to_tx(chan, control);
                        skb_queue_tail(&chan->srej_q, skb);
-                       skb_in_use = 1;
+                       skb_in_use = true;
                        BT_DBG("Queued %p (queue len %d)", skb,
                               skb_queue_len(&chan->srej_q));
 
@@ -5957,7 +6017,7 @@ static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan,
                         * the missing frames.
                         */
                        skb_queue_tail(&chan->srej_q, skb);
-                       skb_in_use = 1;
+                       skb_in_use = true;
                        BT_DBG("Queued %p (queue len %d)", skb,
                               skb_queue_len(&chan->srej_q));
 
@@ -5971,7 +6031,7 @@ static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan,
                         * SREJ'd frames.
                         */
                        skb_queue_tail(&chan->srej_q, skb);
-                       skb_in_use = 1;
+                       skb_in_use = true;
                        BT_DBG("Queued %p (queue len %d)", skb,
                               skb_queue_len(&chan->srej_q));
 
@@ -6380,9 +6440,14 @@ done:
 static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
                                  struct sk_buff *skb)
 {
+       struct hci_conn *hcon = conn->hcon;
        struct l2cap_chan *chan;
 
-       chan = l2cap_global_chan_by_psm(0, psm, conn->src, conn->dst);
+       if (hcon->type != ACL_LINK)
+               goto drop;
+
+       chan = l2cap_global_chan_by_psm(0, psm, &conn->hcon->src,
+                                       &conn->hcon->dst);
        if (!chan)
                goto drop;
 
@@ -6394,6 +6459,10 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
        if (chan->imtu < skb->len)
                goto drop;
 
+       /* Store remote BD_ADDR and PSM for msg_name */
+       bacpy(&bt_cb(skb)->bdaddr, &conn->hcon->dst);
+       bt_cb(skb)->psm = psm;
+
        if (!chan->ops->recv(chan, skb))
                return;
 
@@ -6404,10 +6473,14 @@ drop:
 static void l2cap_att_channel(struct l2cap_conn *conn,
                              struct sk_buff *skb)
 {
+       struct hci_conn *hcon = conn->hcon;
        struct l2cap_chan *chan;
 
+       if (hcon->type != LE_LINK)
+               goto drop;
+
        chan = l2cap_global_chan_by_scid(BT_CONNECTED, L2CAP_CID_ATT,
-                                        conn->src, conn->dst);
+                                        &conn->hcon->src, &conn->hcon->dst);
        if (!chan)
                goto drop;
 
@@ -6441,9 +6514,6 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
        BT_DBG("len %d, cid 0x%4.4x", len, cid);
 
        switch (cid) {
-       case L2CAP_CID_LE_SIGNALING:
-               l2cap_le_sig_channel(conn, skb);
-               break;
        case L2CAP_CID_SIGNALING:
                l2cap_sig_channel(conn, skb);
                break;
@@ -6458,6 +6528,10 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
                l2cap_att_channel(conn, skb);
                break;
 
+       case L2CAP_CID_LE_SIGNALING:
+               l2cap_le_sig_channel(conn, skb);
+               break;
+
        case L2CAP_CID_SMP:
                if (smp_sig_channel(conn, skb))
                        l2cap_conn_del(conn->hcon, EACCES);
@@ -6481,17 +6555,15 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
        /* Find listening sockets and check their link_mode */
        read_lock(&chan_list_lock);
        list_for_each_entry(c, &chan_list, global_l) {
-               struct sock *sk = c->sk;
-
                if (c->state != BT_LISTEN)
                        continue;
 
-               if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
+               if (!bacmp(&c->src, &hdev->bdaddr)) {
                        lm1 |= HCI_LM_ACCEPT;
                        if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
                                lm1 |= HCI_LM_MASTER;
                        exact++;
-               } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
+               } else if (!bacmp(&c->src, BDADDR_ANY)) {
                        lm2 |= HCI_LM_ACCEPT;
                        if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
                                lm2 |= HCI_LM_MASTER;
@@ -6597,11 +6669,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 
                if (!status && (chan->state == BT_CONNECTED ||
                                chan->state == BT_CONFIG)) {
-                       struct sock *sk = chan->sk;
-
-                       clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
-                       sk->sk_state_change(sk);
-
+                       chan->ops->resume(chan);
                        l2cap_check_encryption(chan, encrypt);
                        l2cap_chan_unlock(chan);
                        continue;
@@ -6621,8 +6689,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                        lock_sock(sk);
 
                        if (!status) {
-                               if (test_bit(BT_SK_DEFER_SETUP,
-                                            &bt_sk(sk)->flags)) {
+                               if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
                                        res = L2CAP_CR_PEND;
                                        stat = L2CAP_CS_AUTHOR_PEND;
                                        chan->ops->defer(chan);
@@ -6756,9 +6823,13 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
                conn->rx_len -= skb->len;
 
                if (!conn->rx_len) {
-                       /* Complete frame received */
-                       l2cap_recv_frame(conn, conn->rx_skb);
+                       /* Complete frame received. l2cap_recv_frame
+                        * takes ownership of the skb so set the global
+                        * rx_skb pointer to NULL first.
+                        */
+                       struct sk_buff *rx_skb = conn->rx_skb;
                        conn->rx_skb = NULL;
+                       l2cap_recv_frame(conn, rx_skb);
                }
                break;
        }
@@ -6775,10 +6846,8 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
        read_lock(&chan_list_lock);
 
        list_for_each_entry(c, &chan_list, global_l) {
-               struct sock *sk = c->sk;
-
                seq_printf(f, "%pMR %pMR %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
-                          &bt_sk(sk)->src, &bt_sk(sk)->dst,
+                          &c->src, &c->dst,
                           c->state, __le16_to_cpu(c->psm),
                           c->scid, c->dcid, c->imtu, c->omtu,
                           c->sec_level, c->mode);