Bluetooth: Terminate the link if pairing is cancelled
authorManish Mandlik <mmandlik@google.com>
Wed, 17 Jun 2020 14:39:19 +0000 (16:39 +0200)
committerJohan Hedberg <johan.hedberg@intel.com>
Thu, 18 Jun 2020 10:12:12 +0000 (13:12 +0300)
If user decides to cancel the ongoing pairing process (e.g. by clicking
the cancel button on pairing/passkey window), abort any ongoing pairing
and then terminate the link if it was created because of the pair
device action.

Signed-off-by: Manish Mandlik <mmandlik@google.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
include/net/bluetooth/hci_core.h
net/bluetooth/hci_conn.c
net/bluetooth/l2cap_core.c
net/bluetooth/mgmt.c

index 5240575..77d2934 100644 (file)
@@ -564,6 +564,12 @@ struct hci_dev {
 
 #define HCI_PHY_HANDLE(handle) (handle & 0xff)
 
+enum conn_reasons {
+       CONN_REASON_PAIR_DEVICE,
+       CONN_REASON_L2CAP_CHAN,
+       CONN_REASON_SCO_CONNECT,
+};
+
 struct hci_conn {
        struct list_head list;
 
@@ -615,6 +621,8 @@ struct hci_conn {
        __s8            max_tx_power;
        unsigned long   flags;
 
+       enum conn_reasons conn_reason;
+
        __u32           clock;
        __u16           clock_accuracy;
 
@@ -1040,12 +1048,14 @@ struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle);
 
 struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
                                     u8 dst_type, u8 sec_level,
-                                    u16 conn_timeout);
+                                    u16 conn_timeout,
+                                    enum conn_reasons conn_reason);
 struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
                                u8 dst_type, u8 sec_level, u16 conn_timeout,
                                u8 role, bdaddr_t *direct_rpa);
 struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
-                                u8 sec_level, u8 auth_type);
+                                u8 sec_level, u8 auth_type,
+                                enum conn_reasons conn_reason);
 struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
                                 __u16 setting);
 int hci_conn_check_link_mode(struct hci_conn *conn);
index 9bdffc4..47f3a45 100644 (file)
@@ -1174,7 +1174,8 @@ static int hci_explicit_conn_params_set(struct hci_dev *hdev,
 /* This function requires the caller holds hdev->lock */
 struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
                                     u8 dst_type, u8 sec_level,
-                                    u16 conn_timeout)
+                                    u16 conn_timeout,
+                                    enum conn_reasons conn_reason)
 {
        struct hci_conn *conn;
 
@@ -1219,6 +1220,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
        conn->sec_level = BT_SECURITY_LOW;
        conn->pending_sec_level = sec_level;
        conn->conn_timeout = conn_timeout;
+       conn->conn_reason = conn_reason;
 
        hci_update_background_scan(hdev);
 
@@ -1228,7 +1230,8 @@ done:
 }
 
 struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
-                                u8 sec_level, u8 auth_type)
+                                u8 sec_level, u8 auth_type,
+                                enum conn_reasons conn_reason)
 {
        struct hci_conn *acl;
 
@@ -1248,6 +1251,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
 
        hci_conn_hold(acl);
 
+       acl->conn_reason = conn_reason;
        if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
                acl->sec_level = BT_SECURITY_LOW;
                acl->pending_sec_level = sec_level;
@@ -1264,7 +1268,8 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
        struct hci_conn *acl;
        struct hci_conn *sco;
 
-       acl = hci_connect_acl(hdev, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
+       acl = hci_connect_acl(hdev, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING,
+                             CONN_REASON_SCO_CONNECT);
        if (IS_ERR(acl))
                return acl;
 
index fe913a5..35d2bc5 100644 (file)
@@ -7893,11 +7893,13 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
                else
                        hcon = hci_connect_le_scan(hdev, dst, dst_type,
                                                   chan->sec_level,
-                                                  HCI_LE_CONN_TIMEOUT);
+                                                  HCI_LE_CONN_TIMEOUT,
+                                                  CONN_REASON_L2CAP_CHAN);
 
        } else {
                u8 auth_type = l2cap_get_auth_type(chan);
-               hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type);
+               hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type,
+                                      CONN_REASON_L2CAP_CHAN);
        }
 
        if (IS_ERR(hcon)) {
index ec66160..2a732ca 100644 (file)
@@ -2931,7 +2931,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
 
        if (cp->addr.type == BDADDR_BREDR) {
                conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
-                                      auth_type);
+                                      auth_type, CONN_REASON_PAIR_DEVICE);
        } else {
                u8 addr_type = le_addr_type(cp->addr.type);
                struct hci_conn_params *p;
@@ -2950,9 +2950,9 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
                if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
                        p->auto_connect = HCI_AUTO_CONN_DISABLED;
 
-               conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
-                                          addr_type, sec_level,
-                                          HCI_LE_CONN_TIMEOUT);
+               conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr, addr_type,
+                                          sec_level, HCI_LE_CONN_TIMEOUT,
+                                          CONN_REASON_PAIR_DEVICE);
        }
 
        if (IS_ERR(conn)) {
@@ -3053,6 +3053,20 @@ static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
 
        err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
                                addr, sizeof(*addr));
+
+       /* Since user doesn't want to proceed with the connection, abort any
+        * ongoing pairing and then terminate the link if it was created
+        * because of the pair device action.
+        */
+       if (addr->type == BDADDR_BREDR)
+               hci_remove_link_key(hdev, &addr->bdaddr);
+       else
+               smp_cancel_and_remove_pairing(hdev, &addr->bdaddr,
+                                             le_addr_type(addr->type));
+
+       if (conn->conn_reason == CONN_REASON_PAIR_DEVICE)
+               hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
+
 unlock:
        hci_dev_unlock(hdev);
        return err;