extern struct list_head hci_dev_list;
 extern struct list_head hci_cb_list;
 extern rwlock_t hci_dev_list_lock;
-extern struct mutex hci_cb_list_lock;
 
 #define hci_dev_set_flag(hdev, nr)             set_bit((nr), (hdev)->dev_flags)
 #define hci_dev_clear_flag(hdev, nr)           clear_bit((nr), (hdev)->dev_flags)
 
        char *name;
 
+       bool (*match)           (struct hci_conn *conn);
        void (*connect_cfm)     (struct hci_conn *conn, __u8 status);
        void (*disconn_cfm)     (struct hci_conn *conn, __u8 status);
        void (*security_cfm)    (struct hci_conn *conn, __u8 status,
-                                                               __u8 encrypt);
+                                __u8 encrypt);
        void (*key_change_cfm)  (struct hci_conn *conn, __u8 status);
        void (*role_switch_cfm) (struct hci_conn *conn, __u8 status, __u8 role);
 };
 
+static inline void hci_cb_lookup(struct hci_conn *conn, struct list_head *list)
+{
+       struct hci_cb *cb, *cpy;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(cb, &hci_cb_list, list) {
+               if (cb->match && cb->match(conn)) {
+                       cpy = kmalloc(sizeof(*cpy), GFP_ATOMIC);
+                       if (!cpy)
+                               break;
+
+                       *cpy = *cb;
+                       INIT_LIST_HEAD(&cpy->list);
+                       list_add_rcu(&cpy->list, list);
+               }
+       }
+       rcu_read_unlock();
+}
+
 static inline void hci_connect_cfm(struct hci_conn *conn, __u8 status)
 {
-       struct hci_cb *cb;
+       struct list_head list;
+       struct hci_cb *cb, *tmp;
+
+       INIT_LIST_HEAD(&list);
+       hci_cb_lookup(conn, &list);
 
-       mutex_lock(&hci_cb_list_lock);
-       list_for_each_entry(cb, &hci_cb_list, list) {
+       list_for_each_entry_safe(cb, tmp, &list, list) {
                if (cb->connect_cfm)
                        cb->connect_cfm(conn, status);
+               kfree(cb);
        }
-       mutex_unlock(&hci_cb_list_lock);
 
        if (conn->connect_cfm_cb)
                conn->connect_cfm_cb(conn, status);
 
 static inline void hci_disconn_cfm(struct hci_conn *conn, __u8 reason)
 {
-       struct hci_cb *cb;
+       struct list_head list;
+       struct hci_cb *cb, *tmp;
+
+       INIT_LIST_HEAD(&list);
+       hci_cb_lookup(conn, &list);
 
-       mutex_lock(&hci_cb_list_lock);
-       list_for_each_entry(cb, &hci_cb_list, list) {
+       list_for_each_entry_safe(cb, tmp, &list, list) {
                if (cb->disconn_cfm)
                        cb->disconn_cfm(conn, reason);
+               kfree(cb);
        }
-       mutex_unlock(&hci_cb_list_lock);
 
        if (conn->disconn_cfm_cb)
                conn->disconn_cfm_cb(conn, reason);
 }
 
-static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
+static inline void hci_security_cfm(struct hci_conn *conn, __u8 status,
+                                   __u8 encrypt)
 {
-       struct hci_cb *cb;
-       __u8 encrypt;
-
-       if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
-               return;
+       struct list_head list;
+       struct hci_cb *cb, *tmp;
 
-       encrypt = test_bit(HCI_CONN_ENCRYPT, &conn->flags) ? 0x01 : 0x00;
+       INIT_LIST_HEAD(&list);
+       hci_cb_lookup(conn, &list);
 
-       mutex_lock(&hci_cb_list_lock);
-       list_for_each_entry(cb, &hci_cb_list, list) {
+       list_for_each_entry_safe(cb, tmp, &list, list) {
                if (cb->security_cfm)
                        cb->security_cfm(conn, status, encrypt);
+               kfree(cb);
        }
-       mutex_unlock(&hci_cb_list_lock);
 
        if (conn->security_cfm_cb)
                conn->security_cfm_cb(conn, status);
 }
 
+static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
+{
+       __u8 encrypt;
+
+       if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
+               return;
+
+       encrypt = test_bit(HCI_CONN_ENCRYPT, &conn->flags) ? 0x01 : 0x00;
+
+       hci_security_cfm(conn, status, encrypt);
+}
+
 static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status)
 {
-       struct hci_cb *cb;
        __u8 encrypt;
 
        if (conn->state == BT_CONFIG) {
                        conn->sec_level = conn->pending_sec_level;
        }
 
-       mutex_lock(&hci_cb_list_lock);
-       list_for_each_entry(cb, &hci_cb_list, list) {
-               if (cb->security_cfm)
-                       cb->security_cfm(conn, status, encrypt);
-       }
-       mutex_unlock(&hci_cb_list_lock);
-
-       if (conn->security_cfm_cb)
-               conn->security_cfm_cb(conn, status);
+       hci_security_cfm(conn, status, encrypt);
 }
 
 static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)
 {
-       struct hci_cb *cb;
+       struct list_head list;
+       struct hci_cb *cb, *tmp;
+
+       INIT_LIST_HEAD(&list);
+       hci_cb_lookup(conn, &list);
 
-       mutex_lock(&hci_cb_list_lock);
-       list_for_each_entry(cb, &hci_cb_list, list) {
+       list_for_each_entry_safe(cb, tmp, &list, list) {
                if (cb->key_change_cfm)
                        cb->key_change_cfm(conn, status);
+               kfree(cb);
        }
-       mutex_unlock(&hci_cb_list_lock);
 }
 
 static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
                                                                __u8 role)
 {
-       struct hci_cb *cb;
+       struct list_head list;
+       struct hci_cb *cb, *tmp;
+
+       INIT_LIST_HEAD(&list);
+       hci_cb_lookup(conn, &list);
 
-       mutex_lock(&hci_cb_list_lock);
-       list_for_each_entry(cb, &hci_cb_list, list) {
+       list_for_each_entry_safe(cb, tmp, &list, list) {
                if (cb->role_switch_cfm)
                        cb->role_switch_cfm(conn, status, role);
+               kfree(cb);
        }
-       mutex_unlock(&hci_cb_list_lock);
 }
 
 static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type)