COMPATIBLE_IOCTL(HCIGETDEVINFO)
 COMPATIBLE_IOCTL(HCIGETCONNLIST)
 COMPATIBLE_IOCTL(HCIGETCONNINFO)
+COMPATIBLE_IOCTL(HCIGETAUTHINFO)
 COMPATIBLE_IOCTL(HCISETRAW)
 COMPATIBLE_IOCTL(HCISETSCAN)
 COMPATIBLE_IOCTL(HCISETAUTH)
 
        HCI_INQUIRY,
 
        HCI_RAW,
-
-       HCI_SECMGR
 };
 
 /* HCI ioctl defines */
 #define HCIGETDEVINFO  _IOR('H', 211, int)
 #define HCIGETCONNLIST _IOR('H', 212, int)
 #define HCIGETCONNINFO _IOR('H', 213, int)
+#define HCIGETAUTHINFO _IOR('H', 215, int)
 
 #define HCISETRAW      _IOW('H', 220, int)
 #define HCISETSCAN     _IOW('H', 221, int)
 #define HCISETACLMTU   _IOW('H', 227, int)
 #define HCISETSCOMTU   _IOW('H', 228, int)
 
-#define HCISETSECMGR   _IOW('H', 230, int)
-
 #define HCIINQUIRY     _IOR('H', 240, int)
 
 /* HCI timeouts */
 #define HCI_LM_RELIABLE        0x0010
 #define HCI_LM_SECURE  0x0020
 
+/* Authentication types */
+#define HCI_AT_NO_BONDING              0x00
+#define HCI_AT_NO_BONDING_MITM         0x01
+#define HCI_AT_DEDICATED_BONDING       0x02
+#define HCI_AT_DEDICATED_BONDING_MITM  0x03
+#define HCI_AT_GENERAL_BONDING         0x04
+#define HCI_AT_GENERAL_BONDING_MITM    0x05
+
 /* -----  HCI Commands ---- */
 #define HCI_OP_INQUIRY                 0x0401
 struct hci_cp_inquiry {
        struct   hci_conn_info conn_info[0];
 };
 
+struct hci_auth_info_req {
+       bdaddr_t bdaddr;
+       __u8     type;
+};
+
 struct hci_inquiry_req {
        __u16 dev_id;
        __u16 flags;
 
        __u16            pkt_type;
        __u16            link_policy;
        __u32            link_mode;
+       __u8             auth_type;
        __u8             power_save;
        unsigned long    pend;
 
 int hci_get_dev_info(void __user *arg);
 int hci_get_conn_list(void __user *arg);
 int hci_get_conn_info(struct hci_dev *hdev, void __user *arg);
+int hci_get_auth_info(struct hci_dev *hdev, void __user *arg);
 int hci_inquiry(void __user *arg);
 
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
 
 {
        BT_DBG("conn %p", conn);
 
+       if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0) {
+               if (!(conn->auth_type & 0x01)) {
+                       conn->auth_type = HCI_AT_GENERAL_BONDING_MITM;
+                       conn->link_mode &= ~HCI_LM_AUTH;
+               }
+       }
+
        if (conn->link_mode & HCI_LM_AUTH)
                return 1;
 
        if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
                struct hci_cp_auth_requested cp;
                cp.handle = cpu_to_le16(conn->handle);
-               hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
+               hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
+                                                       sizeof(cp), &cp);
        }
        return 0;
 }
        BT_DBG("conn %p", conn);
 
        if (conn->link_mode & HCI_LM_ENCRYPT)
-               return 1;
+               return hci_conn_auth(conn);
 
        if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
                return 0;
                struct hci_cp_set_conn_encrypt cp;
                cp.handle  = cpu_to_le16(conn->handle);
                cp.encrypt = 1;
-               hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp);
+               hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
+                                                       sizeof(cp), &cp);
        }
        return 0;
 }
        if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
                struct hci_cp_change_conn_link_key cp;
                cp.handle = cpu_to_le16(conn->handle);
-               hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp);
+               hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
+                                                       sizeof(cp), &cp);
        }
        return 0;
 }
 
        return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
 }
+
+int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
+{
+       struct hci_auth_info_req req;
+       struct hci_conn *conn;
+
+       if (copy_from_user(&req, arg, sizeof(req)))
+               return -EFAULT;
+
+       hci_dev_lock_bh(hdev);
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr);
+       if (conn)
+               req.type = conn->auth_type;
+       hci_dev_unlock_bh(hdev);
+
+       if (!conn)
+               return -ENOENT;
+
+       return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0;
+}
 
 
                return 0;
 
-       case HCISETSECMGR:
-               if (!capable(CAP_NET_ADMIN))
-                       return -EACCES;
-
-               if (arg)
-                       set_bit(HCI_SECMGR, &hdev->flags);
-               else
-                       clear_bit(HCI_SECMGR, &hdev->flags);
-
-               return 0;
-
        case HCIGETCONNINFO:
-               return hci_get_conn_info(hdev, (void __user *)arg);
+               return hci_get_conn_info(hdev, (void __user *) arg);
+
+       case HCIGETAUTHINFO:
+               return hci_get_auth_info(hdev, (void __user *) arg);
 
        default:
                if (hdev->ioctl)
 static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
        struct sock *sk = sock->sk;
-       void __user *argp = (void __user *)arg;
+       void __user *argp = (void __user *) arg;
        int err;
 
        BT_DBG("cmd %x arg %lx", cmd, arg);
 
 static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
 {
        struct l2cap_chan_list *l;
-       struct l2cap_conn *conn = conn = hcon->l2cap_data;
+       struct l2cap_conn *conn = hcon->l2cap_data;
        struct l2cap_conn_rsp rsp;
        struct sock *sk;
        int result;
        read_lock(&l->lock);
 
        for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+               struct l2cap_pinfo *pi = l2cap_pi(sk);
+
                bh_lock_sock(sk);
 
-               if (sk->sk_state != BT_CONNECT2 ||
-                               (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) ||
-                               (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)) {
+               if (sk->sk_state != BT_CONNECT2) {
+                       bh_unlock_sock(sk);
+                       continue;
+               }
+
+               if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) &&
+                                       !(hcon->link_mode & HCI_LM_ENCRYPT)) {
                        bh_unlock_sock(sk);
                        continue;
                }
 
        list_for_each_safe(p, n, &s->dlcs) {
                d = list_entry(p, struct rfcomm_dlc, list);
 
-               if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE))
+               if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) &&
+                               !(conn->link_mode & HCI_LM_ENCRYPT) && !status)
                        continue;
 
                if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))