]> 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 a7d10c3596e38e73770ec4ee2d7d5dbebb711869..0c3446da1ec9d7f6765c7f4523ad08c6bd20dbe3 100644 (file)
@@ -43,8 +43,8 @@
 
 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);
@@ -59,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,
@@ -149,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;
@@ -621,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:
@@ -635,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
@@ -647,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);
@@ -677,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;
@@ -686,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;
@@ -703,6 +730,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
                default:
                        return HCI_AT_NO_BONDING;
                }
+               break;
        }
 }
 
@@ -1241,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) {
@@ -1274,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);
@@ -1325,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;
 
@@ -1335,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;
@@ -1365,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;
 
@@ -1383,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);
 
@@ -1649,9 +1676,6 @@ 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)
@@ -1708,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;
 
@@ -1718,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;
@@ -1743,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;
 
@@ -1810,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;
@@ -1845,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);
@@ -2283,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);
 
@@ -2298,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)) {
@@ -3744,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;
@@ -3782,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;
@@ -3798,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;
@@ -4462,7 +4487,8 @@ 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 -EBADSLT;
@@ -4905,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;
        }
@@ -6420,7 +6446,8 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
        if (hcon->type != ACL_LINK)
                goto drop;
 
-       chan = l2cap_global_chan_by_psm(0, psm, conn->src, conn->dst);
+       chan = l2cap_global_chan_by_psm(0, psm, &conn->hcon->src,
+                                       &conn->hcon->dst);
        if (!chan)
                goto drop;
 
@@ -6432,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;
 
@@ -6449,7 +6480,7 @@ static void l2cap_att_channel(struct l2cap_conn *conn,
                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;
 
@@ -6524,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;
@@ -6640,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;
@@ -6664,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);
@@ -6822,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);