Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/blueto...
authorJohn W. Linville <linville@tuxdriver.com>
Thu, 12 May 2011 18:06:10 +0000 (14:06 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 12 May 2011 18:06:10 +0000 (14:06 -0400)
drivers/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
net/bluetooth/hci_conn.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/core.c

index 695d4414bd4c31f060fc0cef81daad90de36a1f9..6bacef368fab2a61750751b7ead7d0673b0e8aea 100644 (file)
@@ -62,6 +62,7 @@ static struct usb_device_id ath3k_table[] = {
 
        /* Atheros AR3011 with sflash firmware*/
        { USB_DEVICE(0x0CF3, 0x3002) },
+       { USB_DEVICE(0x13d3, 0x3304) },
 
        /* Atheros AR9285 Malbec with sflash firmware */
        { USB_DEVICE(0x03F0, 0x311D) },
index 762a5109c68ac24c3c6e83cb462429059528ebac..c2de8951e3fbe11ab876df9c12705548c0fead42 100644 (file)
@@ -104,6 +104,7 @@ static struct usb_device_id blacklist_table[] = {
 
        /* Atheros 3011 with sflash firmware */
        { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
+       { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
 
        /* Atheros AR9285 Malbec with sflash firmware */
        { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
index 14cc3249c1eb04725f7820c32a5dae0c2565b317..6c994c004d15cd0d899ee535be8bc4db9819428b 100644 (file)
@@ -422,6 +422,7 @@ void hci_conn_check_pending(struct hci_dev *hdev);
 
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type);
 int hci_conn_check_link_mode(struct hci_conn *conn);
+int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level);
 int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type);
 int hci_conn_change_link_key(struct hci_conn *conn);
 int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
index c34b1c126363cc4c1ae4f88e32ec634f015d13ec..d09c9b1118e355db1703708d72072cac69a6aa35 100644 (file)
@@ -350,6 +350,7 @@ struct l2cap_chan {
        struct list_head        srej_l;
 
        struct list_head list;
+       struct list_head global_l;
 };
 
 struct l2cap_conn {
@@ -441,7 +442,6 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
 #define __is_sar_start(ctrl)   (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START)
 
 extern int disable_ertm;
-extern struct bt_sock_list l2cap_sk_list;
 
 int l2cap_init_sockets(void);
 void l2cap_cleanup_sockets(void);
@@ -458,6 +458,9 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb);
 void l2cap_streaming_send(struct l2cap_chan *chan);
 int l2cap_ertm_send(struct l2cap_chan *chan);
 
+int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm);
+int l2cap_add_scid(struct l2cap_chan *chan,  __u16 scid);
+
 void l2cap_sock_set_timer(struct sock *sk, long timeout);
 void l2cap_sock_clear_timer(struct sock *sk);
 void __l2cap_sock_close(struct sock *sk, int reason);
@@ -466,9 +469,9 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent);
 struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
                                                        int proto, gfp_t prio);
 void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err);
-struct l2cap_chan *l2cap_chan_alloc(struct sock *sk);
+struct l2cap_chan *l2cap_chan_create(struct sock *sk);
 void l2cap_chan_del(struct l2cap_chan *chan, int err);
-void l2cap_chan_free(struct l2cap_chan *chan);
+void l2cap_chan_destroy(struct l2cap_chan *chan);
 int l2cap_chan_connect(struct l2cap_chan *chan);
 
 #endif /* __L2CAP_H */
index 7f5ad8a2b22d03c2c3eea300cba7dec3b977d20d..3163330cd4f1388e3c0b5d593b5e54ca75ba0c12 100644 (file)
@@ -623,6 +623,23 @@ encrypt:
 }
 EXPORT_SYMBOL(hci_conn_security);
 
+/* Check secure link requirement */
+int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level)
+{
+       BT_DBG("conn %p", conn);
+
+       if (sec_level != BT_SECURITY_HIGH)
+               return 1; /* Accept if non-secure is required */
+
+       if (conn->key_type == HCI_LK_AUTH_COMBINATION ||
+                       (conn->key_type == HCI_LK_COMBINATION &&
+                       conn->pin_length == 16))
+               return 1;
+
+       return 0; /* Reject not secure link */
+}
+EXPORT_SYMBOL(hci_conn_check_secure);
+
 /* Change link key */
 int hci_conn_change_link_key(struct hci_conn *conn)
 {
index d5aa97ee6ffae4ef03e4abce779470d963a957b3..f13ddbf858ba4e90dd92b891d1b13d3fece1d496 100644 (file)
@@ -1440,7 +1440,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
 
        conn->state = BT_CLOSED;
 
-       if (conn->type == ACL_LINK)
+       if (conn->type == ACL_LINK || conn->type == LE_LINK)
                mgmt_disconnected(hdev->id, &conn->dst);
 
        hci_proto_disconn_cfm(conn, ev->reason);
@@ -2659,12 +2659,15 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
        }
 
        if (ev->status) {
+               mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status);
                hci_proto_connect_cfm(conn, ev->status);
                conn->state = BT_CLOSED;
                hci_conn_del(conn);
                goto unlock;
        }
 
+       mgmt_connected(hdev->id, &ev->bdaddr);
+
        conn->handle = __le16_to_cpu(ev->handle);
        conn->state = BT_CONNECTED;
 
index 338d8c3eedabcee2184c2ce70e52641d0393a948..a5ab4a29ae31a1def070592538b720b14d8890c7 100644 (file)
@@ -62,9 +62,8 @@ static u8 l2cap_fixed_chan[8] = { 0x02, };
 
 static struct workqueue_struct *_busy_wq;
 
-struct bt_sock_list l2cap_sk_list = {
-       .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
-};
+LIST_HEAD(chan_list);
+DEFINE_RWLOCK(chan_list_lock);
 
 static void l2cap_busy_work(struct work_struct *work);
 
@@ -135,6 +134,64 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn
        return c;
 }
 
+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))
+                       goto found;
+       }
+
+       c = NULL;
+found:
+       return c;
+}
+
+int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
+{
+       int err;
+
+       write_lock_bh(&chan_list_lock);
+
+       if (psm && __l2cap_global_chan_by_addr(psm, src)) {
+               err = -EADDRINUSE;
+               goto done;
+       }
+
+       if (psm) {
+               chan->psm = psm;
+               chan->sport = psm;
+               err = 0;
+       } else {
+               u16 p;
+
+               err = -EINVAL;
+               for (p = 0x1001; p < 0x1100; p += 2)
+                       if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
+                               chan->psm   = cpu_to_le16(p);
+                               chan->sport = cpu_to_le16(p);
+                               err = 0;
+                               break;
+                       }
+       }
+
+done:
+       write_unlock_bh(&chan_list_lock);
+       return err;
+}
+
+int l2cap_add_scid(struct l2cap_chan *chan,  __u16 scid)
+{
+       write_lock_bh(&chan_list_lock);
+
+       chan->scid = scid;
+
+       write_unlock_bh(&chan_list_lock);
+
+       return 0;
+}
+
 static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
 {
        u16 cid = L2CAP_CID_DYN_START;
@@ -147,7 +204,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
        return 0;
 }
 
-struct l2cap_chan *l2cap_chan_alloc(struct sock *sk)
+struct l2cap_chan *l2cap_chan_create(struct sock *sk)
 {
        struct l2cap_chan *chan;
 
@@ -157,11 +214,19 @@ struct l2cap_chan *l2cap_chan_alloc(struct sock *sk)
 
        chan->sk = sk;
 
+       write_lock_bh(&chan_list_lock);
+       list_add(&chan->global_l, &chan_list);
+       write_unlock_bh(&chan_list_lock);
+
        return chan;
 }
 
-void l2cap_chan_free(struct l2cap_chan *chan)
+void l2cap_chan_destroy(struct l2cap_chan *chan)
 {
+       write_lock_bh(&chan_list_lock);
+       list_del(&chan->global_l);
+       write_unlock_bh(&chan_list_lock);
+
        kfree(chan);
 }
 
@@ -591,48 +656,51 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 /* Find socket with cid and source bdaddr.
  * Returns closest match, locked.
  */
-static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src)
+static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
 {
-       struct sock *sk = NULL, *sk1 = NULL;
-       struct hlist_node *node;
+       struct l2cap_chan *c, *c1 = NULL;
 
-       read_lock(&l2cap_sk_list.lock);
+       read_lock(&chan_list_lock);
 
-       sk_for_each(sk, node, &l2cap_sk_list.head) {
-               struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+       list_for_each_entry(c, &chan_list, global_l) {
+               struct sock *sk = c->sk;
 
                if (state && sk->sk_state != state)
                        continue;
 
-               if (chan->scid == cid) {
+               if (c->scid == cid) {
                        /* Exact match. */
-                       if (!bacmp(&bt_sk(sk)->src, src))
-                               break;
+                       if (!bacmp(&bt_sk(sk)->src, src)) {
+                               read_unlock(&chan_list_lock);
+                               return c;
+                       }
 
                        /* Closest match */
                        if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
-                               sk1 = sk;
+                               c1 = c;
                }
        }
 
-       read_unlock(&l2cap_sk_list.lock);
+       read_unlock(&chan_list_lock);
 
-       return node ? sk : sk1;
+       return c1;
 }
 
 static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 {
        struct sock *parent, *sk;
-       struct l2cap_chan *chan;
+       struct l2cap_chan *chan, *pchan;
 
        BT_DBG("");
 
        /* Check if we have socket listening on cid */
-       parent = l2cap_get_sock_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
+       pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
                                                        conn->src);
-       if (!parent)
+       if (!pchan)
                return;
 
+       parent = pchan->sk;
+
        bh_lock_sock(parent);
 
        /* Check for backlog size */
@@ -645,7 +713,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
        if (!sk)
                goto clean;
 
-       chan = l2cap_chan_alloc(sk);
+       chan = l2cap_chan_create(sk);
        if (!chan) {
                l2cap_sock_kill(sk);
                goto clean;
@@ -823,33 +891,34 @@ static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *ch
 /* Find socket with psm and source bdaddr.
  * Returns closest match.
  */
-static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src)
+static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
 {
-       struct sock *sk = NULL, *sk1 = NULL;
-       struct hlist_node *node;
+       struct l2cap_chan *c, *c1 = NULL;
 
-       read_lock(&l2cap_sk_list.lock);
+       read_lock(&chan_list_lock);
 
-       sk_for_each(sk, node, &l2cap_sk_list.head) {
-               struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+       list_for_each_entry(c, &chan_list, global_l) {
+               struct sock *sk = c->sk;
 
                if (state && sk->sk_state != state)
                        continue;
 
-               if (chan->psm == psm) {
+               if (c->psm == psm) {
                        /* Exact match. */
-                       if (!bacmp(&bt_sk(sk)->src, src))
-                               break;
+                       if (!bacmp(&bt_sk(sk)->src, src)) {
+                               read_unlock_bh(&chan_list_lock);
+                               return c;
+                       }
 
                        /* Closest match */
                        if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
-                               sk1 = sk;
+                               c1 = c;
                }
        }
 
-       read_unlock(&l2cap_sk_list.lock);
+       read_unlock(&chan_list_lock);
 
-       return node ? sk : sk1;
+       return c1;
 }
 
 int l2cap_chan_connect(struct l2cap_chan *chan)
@@ -2019,7 +2088,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 {
        struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
        struct l2cap_conn_rsp rsp;
-       struct l2cap_chan *chan = NULL;
+       struct l2cap_chan *chan = NULL, *pchan;
        struct sock *parent, *sk = NULL;
        int result, status = L2CAP_CS_NO_INFO;
 
@@ -2029,12 +2098,14 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
        BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
 
        /* Check if we have socket listening on psm */
-       parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src);
-       if (!parent) {
+       pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
+       if (!pchan) {
                result = L2CAP_CR_BAD_PSM;
                goto sendresp;
        }
 
+       parent = pchan->sk;
+
        bh_lock_sock(parent);
 
        /* Check if the ACL is secure enough (if not SDP) */
@@ -2057,7 +2128,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
        if (!sk)
                goto response;
 
-       chan = l2cap_chan_alloc(sk);
+       chan = l2cap_chan_create(sk);
        if (!chan) {
                l2cap_sock_kill(sk);
                goto response;
@@ -3685,11 +3756,14 @@ done:
 static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
 {
        struct sock *sk;
+       struct l2cap_chan *chan;
 
-       sk = l2cap_get_sock_by_psm(0, psm, conn->src);
-       if (!sk)
+       chan = l2cap_global_chan_by_psm(0, psm, conn->src);
+       if (!chan)
                goto drop;
 
+       sk = chan->sk;
+
        bh_lock_sock(sk);
 
        BT_DBG("sk %p, len %d", sk, skb->len);
@@ -3715,11 +3789,14 @@ done:
 static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
 {
        struct sock *sk;
+       struct l2cap_chan *chan;
 
-       sk = l2cap_get_sock_by_scid(0, cid, conn->src);
-       if (!sk)
+       chan = l2cap_global_chan_by_scid(0, cid, conn->src);
+       if (!chan)
                goto drop;
 
+       sk = chan->sk;
+
        bh_lock_sock(sk);
 
        BT_DBG("sk %p, len %d", sk, skb->len);
@@ -3786,8 +3863,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 {
        int exact = 0, lm1 = 0, lm2 = 0;
-       register struct sock *sk;
-       struct hlist_node *node;
+       struct l2cap_chan *c;
 
        if (type != ACL_LINK)
                return -EINVAL;
@@ -3795,25 +3871,25 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
        BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
 
        /* Find listening sockets and check their link_mode */
-       read_lock(&l2cap_sk_list.lock);
-       sk_for_each(sk, node, &l2cap_sk_list.head) {
-               struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+       read_lock(&chan_list_lock);
+       list_for_each_entry(c, &chan_list, global_l) {
+               struct sock *sk = c->sk;
 
                if (sk->sk_state != BT_LISTEN)
                        continue;
 
                if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
                        lm1 |= HCI_LM_ACCEPT;
-                       if (chan->role_switch)
+                       if (c->role_switch)
                                lm1 |= HCI_LM_MASTER;
                        exact++;
                } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
                        lm2 |= HCI_LM_ACCEPT;
-                       if (chan->role_switch)
+                       if (c->role_switch)
                                lm2 |= HCI_LM_MASTER;
                }
        }
-       read_unlock(&l2cap_sk_list.lock);
+       read_unlock(&chan_list_lock);
 
        return exact ? lm1 : lm2;
 }
@@ -4066,25 +4142,22 @@ drop:
 
 static int l2cap_debugfs_show(struct seq_file *f, void *p)
 {
-       struct sock *sk;
-       struct hlist_node *node;
+       struct l2cap_chan *c;
 
-       read_lock_bh(&l2cap_sk_list.lock);
+       read_lock_bh(&chan_list_lock);
 
-       sk_for_each(sk, node, &l2cap_sk_list.head) {
-               struct l2cap_pinfo *pi = l2cap_pi(sk);
-               struct l2cap_chan *chan = pi->chan;
+       list_for_each_entry(c, &chan_list, global_l) {
+               struct sock *sk = c->sk;
 
                seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
                                        batostr(&bt_sk(sk)->src),
                                        batostr(&bt_sk(sk)->dst),
-                                       sk->sk_state, __le16_to_cpu(chan->psm),
-                                       chan->scid, chan->dcid,
-                                       chan->imtu, chan->omtu, chan->sec_level,
-                                       chan->mode);
+                                       sk->sk_state, __le16_to_cpu(c->psm),
+                                       c->scid, c->dcid, c->imtu, c->omtu,
+                                       c->sec_level, c->mode);
        }
 
-       read_unlock_bh(&l2cap_sk_list.lock);
+       read_unlock_bh(&chan_list_lock);
 
        return 0;
 }
index 09cc7a0053491c80160855b251acbda436290d25..c98360d40b84dab773a8d2ee3e6c9a11258b30d3 100644 (file)
@@ -78,22 +78,6 @@ void l2cap_sock_clear_timer(struct sock *sk)
        sk_stop_timer(sk, &sk->sk_timer);
 }
 
-static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
-{
-       struct sock *sk;
-       struct hlist_node *node;
-       sk_for_each(sk, node, &l2cap_sk_list.head) {
-               struct l2cap_chan *chan = l2cap_pi(sk)->chan;
-
-               if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src))
-                       goto found;
-       }
-
-       sk = NULL;
-found:
-       return sk;
-}
-
 static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 {
        struct sock *sk = sock->sk;
@@ -136,26 +120,20 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
                }
        }
 
-       write_lock_bh(&l2cap_sk_list.lock);
+       if (la.l2_cid)
+               err = l2cap_add_scid(chan, la.l2_cid);
+       else
+               err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm);
 
-       if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) {
-               err = -EADDRINUSE;
-       } else {
-               /* Save source address */
-               bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
-               chan->psm   = la.l2_psm;
-               chan->sport = la.l2_psm;
-               sk->sk_state = BT_BOUND;
-
-               if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
-                                       __le16_to_cpu(la.l2_psm) == 0x0003)
-                       chan->sec_level = BT_SECURITY_SDP;
-       }
+       if (err < 0)
+               goto done;
 
-       if (la.l2_cid)
-               chan->scid = la.l2_cid;
+       if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
+                               __le16_to_cpu(la.l2_psm) == 0x0003)
+               chan->sec_level = BT_SECURITY_SDP;
 
-       write_unlock_bh(&l2cap_sk_list.lock);
+       bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
+       sk->sk_state = BT_BOUND;
 
 done:
        release_sock(sk);
@@ -278,28 +256,6 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
                goto done;
        }
 
-       if (!chan->psm && !chan->scid) {
-               bdaddr_t *src = &bt_sk(sk)->src;
-               u16 psm;
-
-               err = -EINVAL;
-
-               write_lock_bh(&l2cap_sk_list.lock);
-
-               for (psm = 0x1001; psm < 0x1100; psm += 2)
-                       if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) {
-                               chan->psm   = cpu_to_le16(psm);
-                               chan->sport = cpu_to_le16(psm);
-                               err = 0;
-                               break;
-                       }
-
-               write_unlock_bh(&l2cap_sk_list.lock);
-
-               if (err < 0)
-                       goto done;
-       }
-
        sk->sk_max_ack_backlog = backlog;
        sk->sk_ack_backlog = 0;
        sk->sk_state = BT_LISTEN;
@@ -852,8 +808,7 @@ void l2cap_sock_kill(struct sock *sk)
 
        /* Kill poor orphan */
 
-       l2cap_chan_free(l2cap_pi(sk)->chan);
-       bt_sock_unlink(&l2cap_sk_list, sk);
+       l2cap_chan_destroy(l2cap_pi(sk)->chan);
        sock_set_flag(sk, SOCK_DEAD);
        sock_put(sk);
 }
@@ -1069,7 +1024,6 @@ struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, g
 
        setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk);
 
-       bt_sock_link(&l2cap_sk_list, sk);
        return sk;
 }
 
@@ -1096,7 +1050,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
        if (!sk)
                return -ENOMEM;
 
-       chan = l2cap_chan_alloc(sk);
+       chan = l2cap_chan_create(sk);
        if (!chan) {
                l2cap_sock_kill(sk);
                return -ENOMEM;
index 2481d257ed98058c644f5553bf41132a5793dba7..dae382ce70201d5f4adbacde509c665c467d95ac 100644 (file)
@@ -1033,6 +1033,9 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
        }
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
+       if (!conn)
+               conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
+
        if (!conn) {
                err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
                goto failed;
index 121a5c13b98933d9634009173ea502c7ed7b48d0..5759bb7054f7f4aca8822271b7de4da8997af915 100644 (file)
@@ -2096,7 +2096,7 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
                if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
                        continue;
 
-               if (!status)
+               if (!status && hci_conn_check_secure(conn, d->sec_level))
                        set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
                else
                        set_bit(RFCOMM_AUTH_REJECT, &d->flags);